pluginconf.d/sim.conf000064400000000040147207275600010575 0ustar00require-root-privilege = false; lsmd.conf000064400000000044147207275600006362 0ustar00allow-plugin-root-privilege = true; __init__.py000064400000002462147576505410006677 0ustar00# Copyright (C) 2011-2016 Red Hat, Inc. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . from lsm.version import VERSION from lsm._common import error, info, LsmError, ErrorNumber, \ JobStatus, uri_parse, md5, Proxy, size_bytes_2_size_human, \ common_urllib2_error_handler, size_human_2_size_bytes, int_div from lsm._local_disk import LocalDisk from lsm._data import (Disk, Volume, Pool, System, FileSystem, FsSnapshot, NfsExport, BlockRange, AccessGroup, TargetPort, Capabilities, Battery) from lsm._iplugin import IPlugin, IStorageAreaNetwork, \ INetworkAttachedStorage, INfs from lsm._client import Client from lsm._pluginrunner import PluginRunner, search_property __all__ = [] _common.pyc000064400000042405147576505410006733 0ustar00 -P`c@sddlZddlZddlZddlZddlZddlZyddlmZWn!ek rddl mZnXddl Z y*ddl m Z m Z ddlmZWn7ek rddlm Z m Z ddlmZnXddlZddlZddlZddlZddlZeddZdZdefdYZd ZeZid d 6dRd6dSd6dTd6dUd6dVd6dWd6dXd6dYd6dZd6d[d6d\d6d]d6d^d 6d_d"6d`d#6dad$6dbd&6dcd(6ddd)6ded*6dfd,6dgd.6dhd/6did06Zd,d&d dddgZe d1Z!d2Z"d3Z#ddd4Z$d5Z%d6Z&d7Z'd8Z(d9Z)d:Z*d;Z+d<e,fd=YZ-ed>d?d@edAd?dBedCd?dDdEe,fdFYZ.dddGZ/dHZ0dIefdJYZ1dKefdLYZ2dMZ3dNZ4dOej5fdPYZ6e7dQkrej8ndS(jiN(tSequence(tURLErrort HTTPError(turlparsecs_dfd}fd}t||r:|ndd|fd}|S(s Creates the get/set properties for the given name. It assumes that the actual attribute is '_' + name TODO: Expand this with domain validation to ensure the values are correct. t_cs t|S(N(tgetattr(tself(tattribute_name(s//usr/lib/python2.7/site-packages/lsm/_common.pytgetter9scst||dS(N(tsetattr(Rtvalue(R(s//usr/lib/python2.7/site-packages/lsm/_common.pytsetter<scst||S(N(R (tcls(tnametprop(s//usr/lib/python2.7/site-packages/lsm/_common.pyt decoratorAsN(tpropertytNone(R t allow_settdocRR R((RR Rs//usr/lib/python2.7/site-packages/lsm/_common.pytdefault_property0s  !cCst|tr*ttjt|nt|trt|}d|krd|krrttjdnd|krttjdqnt dt j ttj |nyAt jrt|t jrttj dt|qnWntk rnXtjrGt|trGttjt|nt|tj rtttjt|nt j }t d|ttjd tt||dS( Ns urlopen errors Errno 111sConnection refuseds Errno 113s Host is downsUnexpected network error: sSSL Certificate error (%s)sUnexpected exception: sUnexpected exception (TYPE= %s)(t isinstanceRtLsmErrort ErrorNumbertPLUGIN_AUTH_FAILEDtstrRtNETWORK_CONNREFUSEDtNETWORK_HOSTDOWNterrort tracebackt format_exct NETWORK_ERRORtssltCertificateErrortAttributeErrortsixtPY3tConnectionErrortsockett PLUGIN_BUGttype(texptdesct stack_trace((s//usr/lib/python2.7/site-packages/lsm/_common.pytcommon_urllib2_error_handlerHs:            tProxycBs,eZdZddZdZdZRS(sQ Used to provide an unambiguous error when a feature is not implemented. cCs ||_dS(s< Constructor which takes an object to wrap. N(t proxied_obj(Rtobj((s//usr/lib/python2.7/site-packages/lsm/_common.pyt__init__{scCs;t|j|r%tj|j|SttjddS(sJ Called each time an attribute is requested of the object sUnsupported operationN(thasattrR.t functoolstpartialt_presentRRt NO_SUPPORT(RR ((s//usr/lib/python2.7/site-packages/lsm/_common.pyt __getattr__s cOst|j|||S(sQ Method which is called to invoke the actual method of interest. (RR.(Rt_proxy_method_nametargstkwargs((s//usr/lib/python2.7/site-packages/lsm/_common.pyR4sN(t__name__t __module__t__doc__RR0R6R4(((s//usr/lib/python2.7/site-packages/lsm/_common.pyR-ss s/var/run/lsm/ipcitBii tKiBitKBtKtkitMiBitMBtMtmitGiBi tGBtGtgi(tTiBi tTBtTtti2tPiBitPBtPtpi<tEiBitEBtEtecCspd}|rhx<tD]4}|t|kr|tt|:}|}PqqW|sZd}nd||fS|SdS(s  Convert size in bytes to human readable size The return string will follow IEC binary prefixes, e.g. '1.9 KiB' For size less than 1024, we do nothing but return the int we get. TODO: Need a expect to handle when size is not a int. int() might do. R=s%.2f %sN(RtSIZE_CONS_CHK_LSTt SIZE_CONStfloat(tsizethumantunitstkey_name((s//usr/lib/python2.7/site-packages/lsm/_common.pytshs  cCs t|tS(s Convert integer size in bytes to human readable size. We are following rules of IEC binary prefixes on size: http://en.wikipedia.org/wiki/Gibibyte The biggest of unit this function supported is PiB. The precision is 2 which means you will get '1.99 KiB' (R]tTrue(RY((s//usr/lib/python2.7/site-packages/lsm/_common.pytsize_bytes_2_size_humanscCstjdtj}|j|}d}|r|jd}|jd}|s^t|S|j}|jdd}|tkrt|t |}qnt|S(s Convert human readable size string into integer size in bytes. Following rules of IEC binary prefixes on size: http://en.wikipedia.org/wiki/Gibibyte Supported input size_human in these formats: '1.9KiB' # int(1024*1.9) '1 KiB' # 2**10 '1B' # 1 '2K' # 2*(2**10), treated as '2KiB' '2k' # 2*(2**10), treated as '2KiB' '2KB' # 2*(10**3) s ^ ([0-9\.]+) # 1: number [ \t]* # might have space between number and unit ([a-zA-Z]*) # 2: units $ iiitIBtiB( tretcompiletXtmatchtgrouptinttuppertreplaceRWRX(t size_humantregex_size_humant regex_matcht size_bytestnumberR[((s//usr/lib/python2.7/site-packages/lsm/_common.pytsize_human_2_size_bytess    cCsiy3i}t|}|jr.|j|d|jdD]-}t|rtj||d|qqWdS(s If a message includes new lines we will create multiple syslog entries so that the message is readable. Otherwise it isn't very readable. Hopefully we won't be logging much :-) s s: N(Rtlentsyslog(tleveltprgtmsgtl((s//usr/lib/python2.7/site-packages/lsm/_common.pytpost_msgzs cGs0ttjtjjtjdt|dS(Ni( RRtLOG_ERRtosRtbasenametsystargvR(R((s//usr/lib/python2.7/site-packages/lsm/_common.pyRscGs9tr5ttjtjjtjdt |ndS(Ni( t LOG_VERBOSERRtLOG_INFORRRRRR(R((s//usr/lib/python2.7/site-packages/lsm/_common.pytinfost SocketEOFcBseZdZRS(sL Exception class to indicate when we read zero bytes from a socket. (R:R;R<(((s//usr/lib/python2.7/site-packages/lsm/_common.pyRstcodeRs Error codeRs Error messagetdatasOptional error dataRcBseZddZdZRS(cOs2tj|||||_||_||_dS(s, Class represents an error. N(t ExceptionR0t_codet_msgt_data(RRtmessageRR8R9((s//usr/lib/python2.7/site-packages/lsm/_common.pyR0s  cCsVtj|j}|jdk rA|jrAd||j|jfSd||jfSdS(Ns%s: %s Data: %ss%s: %s (Rterror_number_to_strRRRR(Rt error_no_str((s//usr/lib/python2.7/site-packages/lsm/_common.pyt__str__s N(R:R;RR0R(((s//usr/lib/python2.7/site-packages/lsm/_common.pyRs cCs'i|d6|d6|d6|d6|d6S(sC Used for gathering additional information about an error. tdomainRt exceptiontdebugt debug_data((RRRRR((s//usr/lib/python2.7/site-packages/lsm/_common.pytaddl_error_datascCs|jd}dj|d }t|rat|}x?|dD]}t||}qEWntd}t||}|S(sn Given a class name it returns the class, caller will then need to run the constructor to create. t.iit__main__(RRRt __import__R(t class_nametpartstmoduleREtcomp((s//usr/lib/python2.7/site-packages/lsm/_common.pyt get_classs   RcBs"eZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!d Z"d!Z#d"Z$d#Z%d$Z&d%Z'd&Z(d'Z)d(Z*d)Z+d*Z,e-Z.e/d+Z0RS(,iiiii i i i2i4iei}iiiiiiiiiiiiiiiiiiii,i-i3i7i^iiiiiiiicCsIx>ttjjD]'}tj||krd||fSqWd|S(Ns%s(%d)sUNKNOWN_ERROR_NUMBER(%d)(tlistRt_LOCALStkeys(terror_not error_str((s//usr/lib/python2.7/site-packages/lsm/_common.pyRs(1R:R;tOKtLIB_BUGR't JOB_STARTEDtTIMEOUTtDAEMON_NOT_RUNNINGtPERMISSION_DENIEDt NAME_CONFLICTtEXISTS_INITIATORRxtNO_STATE_CHANGERRRt NO_MEMORYR5t IS_MASKEDtHAS_CHILD_DEPENDENCYtNOT_FOUND_ACCESS_GROUPt NOT_FOUND_FSt NOT_FOUND_JOBtNOT_FOUND_POOLtNOT_FOUND_FS_SStNOT_FOUND_VOLUMEtNOT_FOUND_NFS_EXPORTtNOT_FOUND_SYSTEMtNOT_FOUND_DISKt NOT_LICENSEDtNO_SUPPORT_ONLINE_CHANGEtNO_SUPPORT_OFFLINE_CHANGERtPLUGIN_IPC_FAILtPLUGIN_SOCKET_PERMISSIONtPLUGIN_NOT_EXISTtNOT_ENOUGH_SPACEtTRANSPORT_COMMUNICATIONtTRANSPORT_SERIALIZATIONtTRANSPORT_INVALID_ARGtLAST_INIT_IN_ACCESS_GROUPtUNSUPPORTED_SEARCH_KEYtEMPTY_ACCESS_GROUPtPOOL_NOT_READYt DISK_NOT_FREEtlocalsRt staticmethodR(((s//usr/lib/python2.7/site-packages/lsm/_common.pyRsZ t JobStatuscBseZdZdZdZRS(iii(R:R;t INPROGRESStCOMPLETEtERROR(((s//usr/lib/python2.7/site-packages/lsm/_common.pyRsc CsQt|trt|tsCtd|tt|fnt|dkr}xU|D]}t||d|q\WqMxt||D]\}}t|||qWn|t|krM|dk rMt|t j rt|t j rdSt j | st t|| rMtd|t|tt|fqMndS(Ns6%s call is returning a %s, but is expecting a sequenceiis%s call expected: %s got: %s (RRt TypeErrorRR(Rt type_comparetzipRR#t string_typestinspecttisclasst issubclass(t method_nametexp_typetact_valtavR)tact((s//usr/lib/python2.7/site-packages/lsm/_common.pyR s$  csfd}|S(s4 Decorator function that allows us to ensure that we are getting the correct types back from a function/method call. Note: This is normally frowned upon by the python community, but this API needs to be language agnostic, so making sure we have the correct types is quite important. cs%tjfd}|S(Ncs||}tdkrzt|tkrdtdjtt|fntj|n,tdkrtjd|n|S(Nis.%s call expected %d return values, actual = %di(RRR:R(R8R9R(tfuncttypes(s//usr/lib/python2.7/site-packages/lsm/_common.pytinnerHs%(R2twraps(RR(R(Rs//usr/lib/python2.7/site-packages/lsm/_common.pytouterGs!((RR((Rs//usr/lib/python2.7/site-packages/lsm/_common.pytreturn_requires>s t TestCommoncBs#eZdZdZdZRS(cCsdS(N((R((s//usr/lib/python2.7/site-packages/lsm/_common.pytsetUp`sc Cs y tWn)tk r8}|jt|tnXytdddWnGtk r}|j|jdko|jdko|jdknXtddddd}|j|ddko|ddko|ddko|ddko|ddkdS( Ni tMessagetDataRRRRR(Rt assertTrueRRRRRR(RRUted((s//usr/lib/python2.7/site-packages/lsm/_common.pyt test_simplecs $ &cCsdS(N((R((s//usr/lib/python2.7/site-packages/lsm/_common.pyttearDownws(R:R;RRR(((s//usr/lib/python2.7/site-packages/lsm/_common.pyR_s  Riiiiii@Biii@iʚ;i@i@IIIIIIƤ~IIIId II(9RRtunittestRbRRtcollections.abcRt ImportErrort collectionsRt urllib.errorRRt urllib.parseRturllib2R2RR#R R&R^RRR,tobjectR-tUDS_PATHRRWRVtFalseR]R_RoRRwRRRRRRRRRRRRRRRtTestCaseRR:tmain(((s//usr/lib/python2.7/site-packages/lsm/_common.pyts               +)    (1     Q  ! lsmcli/data_display.pyc000064400000073525147576505410011234 0ustar00 /P`c@s*ddlZddlmZddlmZmZmZmZmZmZm Z m Z m Z m Z m Z mZmZmZyddlmZWn!ek rddlmZnXdZdZdZdZd Zid ej6d ej6d ej6d ej6dej6dej6Z dZ!idej"6dej#6Z$dZ%i d ej6d ej6dej6d ej6d ej6dej&6dej'6dej(6dej)6dej*6Z+dZ,idej-6dej.6dej/6dej06dej16dej26d ej36Z4id!ej56d"ej66Z7d#Z8d$Z9id%e j:6d&e j;6d'e j<6d(e j=6Z>d)Z?id*e j@6d+e jA6ZBd,ZCid-e jD6d.e jE6d/e jF6d0e jG6d(e jH6ZId1ZJi d(e jK6de jL6d2e jM6d3e jN6d4e jO6d5e jP6d6e jQ6d7e jR6d8e jS6d9e jT6d:e jU6d;e jV6d<e jW6ZXd=ZYid e j6d e j6de j6de j6d e j6d>e jZ6d?e j[6d@e j\6de j&6de j)6dAe j]6dBe j^6dCe j_6dDe j`6ZadEZbid e jc6de jd6dFe je6dGe jf6dHe jg6ZhdIZidJZjidejL6d5ejP6dKejk6dGejl6ZmdLZndMZodNZpdOZqid ejK6dejL6dPejr6dQejs6ZtdRZuid ej6dej6d ej6dSejv6dTejw6dUejx6d ej6d ej6ZydVZzid e j{6dWe j|6dXe j}6dYe j~6dZe j6d[e j6d\e j6Zd]Zd^Zd_efd`YZdaefdbYZdcefddYZdeefdfYZdgefdhYZdiefdjYZdkefdlYZdS(miN(tdatetime(tsize_bytes_2_size_humantLsmErrort ErrorNumbertBatterytSystemtPooltDisktVolumet AccessGroupt FileSystemt FsSnapshott NfsExportt TargetPortt LocalDisk(t OrderedDictt,cCs\y7tjjt|tjjdtjjWntk rWtjdnXdS(Ns i(tsyststdouttwritetstrtflushtIOErrortexit(tmsg((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytout's  cCsg}t|}x8t|jD]$}||@r%|j||q%q%W|dkryt|dkrydt|Stj|S(Nis Unknown(%s)(tinttlisttkeystappendtlenthextBIT_MAP_STRING_SPLITTERtjoin(tbit_mapt conv_dicttrctcur_enum((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt_bit_map_to_str0s  cCs4t|}|t|jkr,||Sd|S(Ns Unknown(%d)(RRR(tint_typeR#((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt_enum_type_to_str<s cCswgt|jD]*\}}|j|jkr|^q}t|dkr]|dSttjd|dS(Nis Failed to convert %s to lsm type(RtitemstlowerRRRtINVALID_ARGUMENT(ttype_strR#tktvR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt _str_to_enumDs $ tUnknowntOKtErrortDegradedsPredictive failuretOthercCs t|tS(N(R&t_SYSTEM_STATUS_CONV(t system_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytsystem_status_to_strWssHW RAIDtHBAcCstj|dS(Nt(t_SYSTEM_MODE_CONVtget(t system_mode((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytsystem_mode_to_strastStoppedtReconstructingt Verifyingt InitializingtGrowingcCs t|tS(N(R&t_POOL_STATUS_CONV(t pool_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytpool_status_to_strsstPOOLtVOLUMEt VOLUME_THINt VOLUME_FULLtFStSYSTEM_RESERVEDtDELTAs Volume Grows Volume ShrinkcCs t|tS(N(R&t_POOL_ELEMENT_TYPE_CONV(t element_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytpool_element_type_to_strscCs t|tS(N(R&t_POOL_UNSUPPORTED_ACTION_CONV(tunsupported_actions((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytpool_unsupported_actions_to_strstDEFAULTtFULLtTHINtUNKNOWNcCs t|tS(N(R/t_VOL_PROVISION_CONV(tvol_provision_str((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytvol_provision_str_to_typestYestNocCs t|tS(N(R(t_VOL_ADMIN_STATE_CONV(tvol_admin_state((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytvol_admin_state_to_strstCLONEtCOPYt MIRROR_SYNCt MIRROR_ASYNCcCs t|tS(N(R/t_VOL_REP_TYPE_CONV(tvol_rep_type_str((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytvol_rep_type_str_to_typestATAtSATAtSAStFCsSCSI Over PCI-E(SSD)tSCSItNL_SAStHDDtSSDtHybrids Remote LUNcCs t|tS(N(R(t_DISK_TYPE_CONV(t disk_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_type_to_strstRemovedtStartingtStoppingt MaintenancetSparet ReconstructtFreecCs t|tS(N(R&t_DISK_STATUS_CONV(t disk_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_status_to_strstWWPNtiSCSIsiSCSI/WWPN MixedcCs t|tS(N(R(t_AG_INIT_TYPE_CONV(t init_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytag_init_type_to_strscCs t|tS(N(R/R~(t init_type_str((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytag_init_type_str_to_lsmstFCoEcCs t|tS(N(R(t_TGT_PORT_TYPE_CONV(t port_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyttgt_port_type_to_strscCsf|dkrdS|tjkr#dS|tjkr6dS|tjkrIdS|tjkr\dSt|S(NR9s No SupportR0sNon-Rotating MediumsRotating Medium Unknown Speed(RtRPM_NO_SUPPORTt RPM_UNKNOWNtRPM_NON_ROTATING_MEDIUMtRPM_ROTATING_UNKNOWN_SPEEDR(trpm((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_rpm_to_strs cCs |dkrdSt|tjS(NR9s No Support(R(t LocalDiskInfot_LINK_TYPE_MAP(t link_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_link_type_to_strs cCs`|dkrdS|tjkr#dS|tjkr6dS|tjkrIdS|tjkr\dSdS(NR9s No SupportR0tFailuretWarningtGood(RtHEALTH_STATUS_UNKNOWNtHEALTH_STATUS_FAILtHEALTH_STATUS_WARNtHEALTH_STATUS_GOOD(t health_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_health_status_to_strs tChemicalt CapacitorcCs t|tS(N(R(t_BATTERY_TYPE_CONV(t battery_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytbattery_type_to_str#st DischargingtChargingtLearningcCs t|tS(N(R&t_BATTERY_STATUS_CONV(tbattery_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytbattery_status_to_str3stIDENT_ONt IDENT_OFFt IDENT_UNKNOWNtFAULT_ONt FAULT_OFFt FAULT_UNKNOWNcCs t|tS(N(R&t_DISK_LED_STATUS_CONV(t led_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_led_status_to_strBscCs%|tjkrdSdt|dS(NR0s %.1f Gbpsg@@(RtLINK_SPEED_UNKNOWNtfloat(t link_speed((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_link_speed_to_strFstPlugDatacBseZdZRS(cCs||_||_dS(N(tdesctversion(tselft descriptiontplugin_version((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt__init__Ms (t__name__t __module__R(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRLstVolumeRAIDInfocBseZidej6dej6dej6dej6dej6dej6dej 6dej 6dej 6d ej 6d ej 6d ej6d ej6d ej6dej6dej6dej6Zdddddd d gZdZedZedZRS(tRAID0tRAID1tRAID3tRAID4tRAID5tRAID6tRAID10tRAID15tRAID16tRAID50tRAID60tRAID51tRAID61tJBODtMIXEDtOTHERRVcCs:||_||_||_||_||_||_dS(N(tvol_idt raid_typet strip_sizet disk_countt min_io_sizet opt_io_size(RRRRRRR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRjs      cCst|tjS(N(R(Rt_RAID_TYPE_MAP(R((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytraid_type_to_strsscCst|tjS(N(R/RR(t raid_type_str((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytraid_type_str_to_lsmws(RRRtRAID_TYPE_RAID0tRAID_TYPE_RAID1tRAID_TYPE_RAID3tRAID_TYPE_RAID4tRAID_TYPE_RAID5tRAID_TYPE_RAID6tRAID_TYPE_RAID10tRAID_TYPE_RAID15tRAID_TYPE_RAID16tRAID_TYPE_RAID50tRAID_TYPE_RAID60tRAID_TYPE_RAID51tRAID_TYPE_RAID61tRAID_TYPE_JBODtRAID_TYPE_MIXEDtRAID_TYPE_OTHERtRAID_TYPE_UNKNOWNRtVOL_CREATE_RAID_TYPES_STRRt staticmethodRR(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRRs,                  t PoolRAIDInfocBsNeZidej6dej6dej6dej6ZdZe dZ RS(R0RRcCs(||_||_||_||_dS(N(tpool_idRt member_typet member_ids(RRRRR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRs   cCst|tjS(N(R(Rt_MEMBER_TYPE_MAP(R((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytmember_type_to_strs( RRRtMEMBER_TYPE_UNKNOWNtMEMBER_TYPE_OTHERtMEMBER_TYPE_POOLtMEMBER_TYPE_DISKRRRR(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyR|s     tVcrCapcBseZdZRS(cCs||_||_||_dS(N(t system_idt raid_typest strip_sizes(RRRR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRs  (RRR(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRsRcBseZi dej6dej6dej6dej6dej6dej6dej 6dej 6dej 6d ej 6d ej 6d ej6d ej6Zd ZRS(s No SupportR0RitSSAtSBPtSRPR}RhtADTs PATA/SATAtUSBsSCSI over PCIEsPCI-Ec CsL||_||_||_||_||_||_||_||_dS(N(tsd_pathtvpd83RRt serial_numRRR( RRRRRRRRR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRs       (RRRtLINK_TYPE_NO_SUPPORTtLINK_TYPE_UNKNOWNt LINK_TYPE_FCt LINK_TYPE_SSAt LINK_TYPE_SBPt LINK_TYPE_SRPtLINK_TYPE_ISCSIt LINK_TYPE_SASt LINK_TYPE_ADTt LINK_TYPE_ATAt LINK_TYPE_USBt LINK_TYPE_SOPtLINK_TYPE_PCIERR(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRs             tVolumeRAMCacheInfocBs$eZidej6dej6dej6dej6Zidej6dej 6dej 6dej 6Z idej 6dej6dej6Zidej6dej6dej6Zidej6dej6dej6ZdZedZed Zed Zed Zed ZRS( sUse Disk SettingtEnabledtDisabledR0s Write BacktAutos Write ThroughcCs:||_||_||_||_||_||_dS(N(Rtwrite_cache_policytwrite_cache_statustread_cache_policytread_cache_statustphy_disk_cache(RRRRRRR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRs      cCst|tjS(N(R(R t_PHY_DISK_CACHE_STATUS_MAP(R((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytphy_disk_cache_status_to_strscCst|tjS(N(R(R t_W_CACHE_POLICY_MAP(t w_cache_p((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytw_cache_policy_to_strscCst|tjS(N(R(R t_W_CACHE_STATUS_MAP(tw_cache_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytw_cache_status_to_strscCst|tjS(N(R(R t_R_CACHE_POLICY_MAP(t r_cache_p((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytr_cache_policy_to_strscCst|tjS(N(R(R t_R_CACHE_STATUS_MAP(tr_cache_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytr_cache_status_to_strs( RRRt$PHYSICAL_DISK_CACHE_USE_DISK_SETTINGtPHYSICAL_DISK_CACHE_ENABLEDtPHYSICAL_DISK_CACHE_DISABLEDtPHYSICAL_DISK_CACHE_UNKNOWNRtWRITE_CACHE_POLICY_UNKNOWNtWRITE_CACHE_POLICY_WRITE_BACKtWRITE_CACHE_POLICY_AUTOt WRITE_CACHE_POLICY_WRITE_THROUGHRtWRITE_CACHE_STATUS_UNKNOWNtWRITE_CACHE_STATUS_WRITE_BACKt WRITE_CACHE_STATUS_WRITE_THROUGHRtREAD_CACHE_POLICY_UNKNOWNtREAD_CACHE_POLICY_ENABLEDtREAD_CACHE_POLICY_DISABLEDRtREAD_CACHE_STATUS_UNKNOWNtREAD_CACHE_STATUS_ENABLEDtREAD_CACHE_STATUS_DISABLEDR RRRRRRR"(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyR s8                  t DisplayDatac Bs eZdZdZdZeZdZiZeZ de d6Z;gZ<ie7d6e8d6e;d6e<d6ee=de>dd@dBdDdFdHdJdLdNdPd6e?d6e@d6eAd6eeB8stPathRs Serial NumberRs LED StatusRs Link SpeedRs Health StatusRttypeR9sWrite Cache PolicyRs Write CacheRsRead Cache PolicyRs Read CacheRsPhysical Disk CacheRcCsyt||}Wn4tk rI}|jtjkr@d}qJ|nX|s~|t|jkr~|||}q~n|r||krt|tkrtd|D}qt|}qn|S(NR9css|]}t|VqdS(N(R(t.0ts((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pys s( tgetattrRtcodeRt NO_SUPPORTRRRgR(tobjtkeyRCRDt flag_humant flag_enumtvaluetlsm_err((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt_get_man_pro_values   cCs]d}xPtdt|D]9}||}t|||krt||}qqW|S(Nii(trangeR(t two_d_listt column_indext max_widtht row_indextrow_data((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt_find_max_widths  cCsBt}tjt|}|d}|d} |d} |rLtj}ng} |tjkrxat|jD]&} | |dkrt| j| qtqtWn$|tjkrt|j} n|rx-|D]"} | | kr| j| qqWnx@| D]8}||}tj ||| | ||}|||s$ ^                                                                                                                    *Elsmcli/__init__.py000064400000001416147576505410010160 0ustar00# Copyright (C) 2011-2016 Red Hat, Inc. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . try: from .cmdline import cmd_line_wrapper except ImportError: from cmdline import cmd_line_wrapper lsmcli/__init__.pyc000064400000000421147576505410010316 0ustar00 /P`c@s<yddlmZWn!ek r7ddlmZnXdS(i(tcmd_line_wrapperiN(tcmdlineRt ImportError(((s7/usr/lib/python2.7/site-packages/lsm/lsmcli/__init__.pyts lsmcli/data_display.pyo000064400000073525147576505410011250 0ustar00 /P`c@s*ddlZddlmZddlmZmZmZmZmZmZm Z m Z m Z m Z m Z mZmZmZyddlmZWn!ek rddlmZnXdZdZdZdZd Zid ej6d ej6d ej6d ej6dej6dej6Z dZ!idej"6dej#6Z$dZ%i d ej6d ej6dej6d ej6d ej6dej&6dej'6dej(6dej)6dej*6Z+dZ,idej-6dej.6dej/6dej06dej16dej26d ej36Z4id!ej56d"ej66Z7d#Z8d$Z9id%e j:6d&e j;6d'e j<6d(e j=6Z>d)Z?id*e j@6d+e jA6ZBd,ZCid-e jD6d.e jE6d/e jF6d0e jG6d(e jH6ZId1ZJi d(e jK6de jL6d2e jM6d3e jN6d4e jO6d5e jP6d6e jQ6d7e jR6d8e jS6d9e jT6d:e jU6d;e jV6d<e jW6ZXd=ZYid e j6d e j6de j6de j6d e j6d>e jZ6d?e j[6d@e j\6de j&6de j)6dAe j]6dBe j^6dCe j_6dDe j`6ZadEZbid e jc6de jd6dFe je6dGe jf6dHe jg6ZhdIZidJZjidejL6d5ejP6dKejk6dGejl6ZmdLZndMZodNZpdOZqid ejK6dejL6dPejr6dQejs6ZtdRZuid ej6dej6d ej6dSejv6dTejw6dUejx6d ej6d ej6ZydVZzid e j{6dWe j|6dXe j}6dYe j~6dZe j6d[e j6d\e j6Zd]Zd^Zd_efd`YZdaefdbYZdcefddYZdeefdfYZdgefdhYZdiefdjYZdkefdlYZdS(miN(tdatetime(tsize_bytes_2_size_humantLsmErrort ErrorNumbertBatterytSystemtPooltDisktVolumet AccessGroupt FileSystemt FsSnapshott NfsExportt TargetPortt LocalDisk(t OrderedDictt,cCs\y7tjjt|tjjdtjjWntk rWtjdnXdS(Ns i(tsyststdouttwritetstrtflushtIOErrortexit(tmsg((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytout's  cCsg}t|}x8t|jD]$}||@r%|j||q%q%W|dkryt|dkrydt|Stj|S(Nis Unknown(%s)(tinttlisttkeystappendtlenthextBIT_MAP_STRING_SPLITTERtjoin(tbit_mapt conv_dicttrctcur_enum((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt_bit_map_to_str0s  cCs4t|}|t|jkr,||Sd|S(Ns Unknown(%d)(RRR(tint_typeR#((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt_enum_type_to_str<s cCswgt|jD]*\}}|j|jkr|^q}t|dkr]|dSttjd|dS(Nis Failed to convert %s to lsm type(RtitemstlowerRRRtINVALID_ARGUMENT(ttype_strR#tktvR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt _str_to_enumDs $ tUnknowntOKtErrortDegradedsPredictive failuretOthercCs t|tS(N(R&t_SYSTEM_STATUS_CONV(t system_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytsystem_status_to_strWssHW RAIDtHBAcCstj|dS(Nt(t_SYSTEM_MODE_CONVtget(t system_mode((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytsystem_mode_to_strastStoppedtReconstructingt Verifyingt InitializingtGrowingcCs t|tS(N(R&t_POOL_STATUS_CONV(t pool_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytpool_status_to_strsstPOOLtVOLUMEt VOLUME_THINt VOLUME_FULLtFStSYSTEM_RESERVEDtDELTAs Volume Grows Volume ShrinkcCs t|tS(N(R&t_POOL_ELEMENT_TYPE_CONV(t element_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytpool_element_type_to_strscCs t|tS(N(R&t_POOL_UNSUPPORTED_ACTION_CONV(tunsupported_actions((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytpool_unsupported_actions_to_strstDEFAULTtFULLtTHINtUNKNOWNcCs t|tS(N(R/t_VOL_PROVISION_CONV(tvol_provision_str((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytvol_provision_str_to_typestYestNocCs t|tS(N(R(t_VOL_ADMIN_STATE_CONV(tvol_admin_state((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytvol_admin_state_to_strstCLONEtCOPYt MIRROR_SYNCt MIRROR_ASYNCcCs t|tS(N(R/t_VOL_REP_TYPE_CONV(tvol_rep_type_str((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytvol_rep_type_str_to_typestATAtSATAtSAStFCsSCSI Over PCI-E(SSD)tSCSItNL_SAStHDDtSSDtHybrids Remote LUNcCs t|tS(N(R(t_DISK_TYPE_CONV(t disk_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_type_to_strstRemovedtStartingtStoppingt MaintenancetSparet ReconstructtFreecCs t|tS(N(R&t_DISK_STATUS_CONV(t disk_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_status_to_strstWWPNtiSCSIsiSCSI/WWPN MixedcCs t|tS(N(R(t_AG_INIT_TYPE_CONV(t init_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytag_init_type_to_strscCs t|tS(N(R/R~(t init_type_str((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytag_init_type_str_to_lsmstFCoEcCs t|tS(N(R(t_TGT_PORT_TYPE_CONV(t port_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyttgt_port_type_to_strscCsf|dkrdS|tjkr#dS|tjkr6dS|tjkrIdS|tjkr\dSt|S(NR9s No SupportR0sNon-Rotating MediumsRotating Medium Unknown Speed(RtRPM_NO_SUPPORTt RPM_UNKNOWNtRPM_NON_ROTATING_MEDIUMtRPM_ROTATING_UNKNOWN_SPEEDR(trpm((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_rpm_to_strs cCs |dkrdSt|tjS(NR9s No Support(R(t LocalDiskInfot_LINK_TYPE_MAP(t link_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_link_type_to_strs cCs`|dkrdS|tjkr#dS|tjkr6dS|tjkrIdS|tjkr\dSdS(NR9s No SupportR0tFailuretWarningtGood(RtHEALTH_STATUS_UNKNOWNtHEALTH_STATUS_FAILtHEALTH_STATUS_WARNtHEALTH_STATUS_GOOD(t health_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_health_status_to_strs tChemicalt CapacitorcCs t|tS(N(R(t_BATTERY_TYPE_CONV(t battery_type((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytbattery_type_to_str#st DischargingtChargingtLearningcCs t|tS(N(R&t_BATTERY_STATUS_CONV(tbattery_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytbattery_status_to_str3stIDENT_ONt IDENT_OFFt IDENT_UNKNOWNtFAULT_ONt FAULT_OFFt FAULT_UNKNOWNcCs t|tS(N(R&t_DISK_LED_STATUS_CONV(t led_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_led_status_to_strBscCs%|tjkrdSdt|dS(NR0s %.1f Gbpsg@@(RtLINK_SPEED_UNKNOWNtfloat(t link_speed((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytdisk_link_speed_to_strFstPlugDatacBseZdZRS(cCs||_||_dS(N(tdesctversion(tselft descriptiontplugin_version((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt__init__Ms (t__name__t __module__R(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRLstVolumeRAIDInfocBseZidej6dej6dej6dej6dej6dej6dej 6dej 6dej 6d ej 6d ej 6d ej6d ej6d ej6dej6dej6dej6Zdddddd d gZdZedZedZRS(tRAID0tRAID1tRAID3tRAID4tRAID5tRAID6tRAID10tRAID15tRAID16tRAID50tRAID60tRAID51tRAID61tJBODtMIXEDtOTHERRVcCs:||_||_||_||_||_||_dS(N(tvol_idt raid_typet strip_sizet disk_countt min_io_sizet opt_io_size(RRRRRRR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRjs      cCst|tjS(N(R(Rt_RAID_TYPE_MAP(R((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytraid_type_to_strsscCst|tjS(N(R/RR(t raid_type_str((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytraid_type_str_to_lsmws(RRRtRAID_TYPE_RAID0tRAID_TYPE_RAID1tRAID_TYPE_RAID3tRAID_TYPE_RAID4tRAID_TYPE_RAID5tRAID_TYPE_RAID6tRAID_TYPE_RAID10tRAID_TYPE_RAID15tRAID_TYPE_RAID16tRAID_TYPE_RAID50tRAID_TYPE_RAID60tRAID_TYPE_RAID51tRAID_TYPE_RAID61tRAID_TYPE_JBODtRAID_TYPE_MIXEDtRAID_TYPE_OTHERtRAID_TYPE_UNKNOWNRtVOL_CREATE_RAID_TYPES_STRRt staticmethodRR(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRRs,                  t PoolRAIDInfocBsNeZidej6dej6dej6dej6ZdZe dZ RS(R0RRcCs(||_||_||_||_dS(N(tpool_idRt member_typet member_ids(RRRRR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRs   cCst|tjS(N(R(Rt_MEMBER_TYPE_MAP(R((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytmember_type_to_strs( RRRtMEMBER_TYPE_UNKNOWNtMEMBER_TYPE_OTHERtMEMBER_TYPE_POOLtMEMBER_TYPE_DISKRRRR(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyR|s     tVcrCapcBseZdZRS(cCs||_||_||_dS(N(t system_idt raid_typest strip_sizes(RRRR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRs  (RRR(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRsRcBseZi dej6dej6dej6dej6dej6dej6dej 6dej 6dej 6d ej 6d ej 6d ej6d ej6Zd ZRS(s No SupportR0RitSSAtSBPtSRPR}RhtADTs PATA/SATAtUSBsSCSI over PCIEsPCI-Ec CsL||_||_||_||_||_||_||_||_dS(N(tsd_pathtvpd83RRt serial_numRRR( RRRRRRRRR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRs       (RRRtLINK_TYPE_NO_SUPPORTtLINK_TYPE_UNKNOWNt LINK_TYPE_FCt LINK_TYPE_SSAt LINK_TYPE_SBPt LINK_TYPE_SRPtLINK_TYPE_ISCSIt LINK_TYPE_SASt LINK_TYPE_ADTt LINK_TYPE_ATAt LINK_TYPE_USBt LINK_TYPE_SOPtLINK_TYPE_PCIERR(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRs             tVolumeRAMCacheInfocBs$eZidej6dej6dej6dej6Zidej6dej 6dej 6dej 6Z idej 6dej6dej6Zidej6dej6dej6Zidej6dej6dej6ZdZedZed Zed Zed Zed ZRS( sUse Disk SettingtEnabledtDisabledR0s Write BacktAutos Write ThroughcCs:||_||_||_||_||_||_dS(N(Rtwrite_cache_policytwrite_cache_statustread_cache_policytread_cache_statustphy_disk_cache(RRRRRRR((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyRs      cCst|tjS(N(R(R t_PHY_DISK_CACHE_STATUS_MAP(R((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytphy_disk_cache_status_to_strscCst|tjS(N(R(R t_W_CACHE_POLICY_MAP(t w_cache_p((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytw_cache_policy_to_strscCst|tjS(N(R(R t_W_CACHE_STATUS_MAP(tw_cache_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytw_cache_status_to_strscCst|tjS(N(R(R t_R_CACHE_POLICY_MAP(t r_cache_p((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytr_cache_policy_to_strscCst|tjS(N(R(R t_R_CACHE_STATUS_MAP(tr_cache_status((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pytr_cache_status_to_strs( RRRt$PHYSICAL_DISK_CACHE_USE_DISK_SETTINGtPHYSICAL_DISK_CACHE_ENABLEDtPHYSICAL_DISK_CACHE_DISABLEDtPHYSICAL_DISK_CACHE_UNKNOWNRtWRITE_CACHE_POLICY_UNKNOWNtWRITE_CACHE_POLICY_WRITE_BACKtWRITE_CACHE_POLICY_AUTOt WRITE_CACHE_POLICY_WRITE_THROUGHRtWRITE_CACHE_STATUS_UNKNOWNtWRITE_CACHE_STATUS_WRITE_BACKt WRITE_CACHE_STATUS_WRITE_THROUGHRtREAD_CACHE_POLICY_UNKNOWNtREAD_CACHE_POLICY_ENABLEDtREAD_CACHE_POLICY_DISABLEDRtREAD_CACHE_STATUS_UNKNOWNtREAD_CACHE_STATUS_ENABLEDtREAD_CACHE_STATUS_DISABLEDR RRRRRRR"(((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyR s8                  t DisplayDatac Bs eZdZdZdZeZdZiZeZ de d6Z;gZ<ie7d6e8d6e;d6e<d6ee=de>dd@dBdDdFdHdJdLdNdPd6e?d6e@d6eAd6eeB8stPathRs Serial NumberRs LED StatusRs Link SpeedRs Health StatusRttypeR9sWrite Cache PolicyRs Write CacheRsRead Cache PolicyRs Read CacheRsPhysical Disk CacheRcCsyt||}Wn4tk rI}|jtjkr@d}qJ|nX|s~|t|jkr~|||}q~n|r||krt|tkrtd|D}qt|}qn|S(NR9css|]}t|VqdS(N(R(t.0ts((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pys s( tgetattrRtcodeRt NO_SUPPORTRRRgR(tobjtkeyRCRDt flag_humant flag_enumtvaluetlsm_err((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt_get_man_pro_values   cCs]d}xPtdt|D]9}||}t|||krt||}qqW|S(Nii(trangeR(t two_d_listt column_indext max_widtht row_indextrow_data((s;/usr/lib/python2.7/site-packages/lsm/lsmcli/data_display.pyt_find_max_widths  cCsBt}tjt|}|d}|d} |d} |rLtj}ng} |tjkrxat|jD]&} | |dkrt| j| qtqtWn$|tjkrt|j} n|rx-|D]"} | | kr| j| qqWnx@| D]8}||}tj ||| | ||}|||s$ ^                                                                                                                    *Elsmcli/data_display.py000064400000110003147576505410011050 0ustar00# Copyright (C) 2014 Red Hat, Inc. # (C) Copyright 2017 Hewlett Packard Enterprise Development LP # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: Gris Ge import sys from datetime import datetime from lsm import (size_bytes_2_size_human, LsmError, ErrorNumber, Battery, System, Pool, Disk, Volume, AccessGroup, FileSystem, FsSnapshot, NfsExport, TargetPort, LocalDisk) try: from collections import OrderedDict except ImportError: # python 2.6 or earlier, use backport from ordereddict import OrderedDict BIT_MAP_STRING_SPLITTER = ',' # Users are reporting errors with broken pipe when piping output # to another program. This appears to be related to this issue: # http://bugs.python.org/issue11380 # Unable to reproduce, but hopefully this will address it. # @param msg The message to be written to stdout def out(msg): try: sys.stdout.write(str(msg)) sys.stdout.write("\n") sys.stdout.flush() except IOError: sys.exit(1) def _bit_map_to_str(bit_map, conv_dict): rc = [] bit_map = int(bit_map) for cur_enum in list(conv_dict.keys()): if cur_enum & bit_map: rc.append(conv_dict[cur_enum]) # If there are no bits set we really don't need a string if bit_map != 0 and len(rc) == 0: return 'Unknown(%s)' % hex(bit_map) return BIT_MAP_STRING_SPLITTER.join(rc) def _enum_type_to_str(int_type, conv_dict): int_type = int(int_type) if int_type in list(conv_dict.keys()): return conv_dict[int_type] return 'Unknown(%d)' % int_type def _str_to_enum(type_str, conv_dict): keys = [k for k, v in list(conv_dict.items()) if v.lower() == type_str.lower()] if len(keys) > 0: return keys[0] raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Failed to convert %s to lsm type" % type_str) _SYSTEM_STATUS_CONV = { System.STATUS_UNKNOWN: 'Unknown', System.STATUS_OK: 'OK', System.STATUS_ERROR: 'Error', System.STATUS_DEGRADED: 'Degraded', System.STATUS_PREDICTIVE_FAILURE: 'Predictive failure', System.STATUS_OTHER: 'Other', } def system_status_to_str(system_status): return _bit_map_to_str(system_status, _SYSTEM_STATUS_CONV) _SYSTEM_MODE_CONV = { System.MODE_HARDWARE_RAID: "HW RAID", System.MODE_HBA: "HBA", } def system_mode_to_str(system_mode): return _SYSTEM_MODE_CONV.get(system_mode, "") _POOL_STATUS_CONV = { Pool.STATUS_UNKNOWN: 'Unknown', Pool.STATUS_OK: 'OK', Pool.STATUS_OTHER: 'Other', Pool.STATUS_DEGRADED: 'Degraded', Pool.STATUS_ERROR: 'Error', Pool.STATUS_STOPPED: 'Stopped', Pool.STATUS_RECONSTRUCTING: 'Reconstructing', Pool.STATUS_VERIFYING: 'Verifying', Pool.STATUS_INITIALIZING: 'Initializing', Pool.STATUS_GROWING: 'Growing', } def pool_status_to_str(pool_status): return _bit_map_to_str(pool_status, _POOL_STATUS_CONV) _POOL_ELEMENT_TYPE_CONV = { Pool.ELEMENT_TYPE_POOL: 'POOL', Pool.ELEMENT_TYPE_VOLUME: 'VOLUME', Pool.ELEMENT_TYPE_VOLUME_THIN: 'VOLUME_THIN', Pool.ELEMENT_TYPE_VOLUME_FULL: 'VOLUME_FULL', Pool.ELEMENT_TYPE_FS: 'FS', Pool.ELEMENT_TYPE_SYS_RESERVED: 'SYSTEM_RESERVED', Pool.ELEMENT_TYPE_DELTA: "DELTA", } _POOL_UNSUPPORTED_ACTION_CONV = { Pool.UNSUPPORTED_VOLUME_GROW: "Volume Grow", Pool.UNSUPPORTED_VOLUME_SHRINK: "Volume Shrink" } def pool_element_type_to_str(element_type): return _bit_map_to_str(element_type, _POOL_ELEMENT_TYPE_CONV) def pool_unsupported_actions_to_str(unsupported_actions): return _bit_map_to_str(unsupported_actions, _POOL_UNSUPPORTED_ACTION_CONV) _VOL_PROVISION_CONV = { Volume.PROVISION_DEFAULT: 'DEFAULT', Volume.PROVISION_FULL: 'FULL', Volume.PROVISION_THIN: 'THIN', Volume.PROVISION_UNKNOWN: 'UNKNOWN', } def vol_provision_str_to_type(vol_provision_str): return _str_to_enum(vol_provision_str, _VOL_PROVISION_CONV) _VOL_ADMIN_STATE_CONV = { Volume.ADMIN_STATE_DISABLED: 'Yes', Volume.ADMIN_STATE_ENABLED: 'No', } def vol_admin_state_to_str(vol_admin_state): return _enum_type_to_str(vol_admin_state, _VOL_ADMIN_STATE_CONV) _VOL_REP_TYPE_CONV = { Volume.REPLICATE_CLONE: 'CLONE', Volume.REPLICATE_COPY: 'COPY', Volume.REPLICATE_MIRROR_SYNC: 'MIRROR_SYNC', Volume.REPLICATE_MIRROR_ASYNC: 'MIRROR_ASYNC', Volume.REPLICATE_UNKNOWN: 'UNKNOWN', } def vol_rep_type_str_to_type(vol_rep_type_str): return _str_to_enum(vol_rep_type_str, _VOL_REP_TYPE_CONV) _DISK_TYPE_CONV = { Disk.TYPE_UNKNOWN: 'UNKNOWN', Disk.TYPE_OTHER: 'Other', Disk.TYPE_ATA: 'ATA', Disk.TYPE_SATA: 'SATA', Disk.TYPE_SAS: 'SAS', Disk.TYPE_FC: 'FC', Disk.TYPE_SOP: 'SCSI Over PCI-E(SSD)', Disk.TYPE_SCSI: 'SCSI', Disk.TYPE_NL_SAS: 'NL_SAS', Disk.TYPE_HDD: 'HDD', Disk.TYPE_SSD: 'SSD', Disk.TYPE_HYBRID: 'Hybrid', Disk.TYPE_LUN: 'Remote LUN', } def disk_type_to_str(disk_type): return _enum_type_to_str(disk_type, _DISK_TYPE_CONV) _DISK_STATUS_CONV = { Disk.STATUS_UNKNOWN: 'Unknown', Disk.STATUS_OK: 'OK', Disk.STATUS_OTHER: 'Other', Disk.STATUS_PREDICTIVE_FAILURE: 'Predictive failure', Disk.STATUS_ERROR: 'Error', Disk.STATUS_REMOVED: 'Removed', Disk.STATUS_STARTING: 'Starting', Disk.STATUS_STOPPING: 'Stopping', Disk.STATUS_STOPPED: 'Stopped', Disk.STATUS_INITIALIZING: 'Initializing', Disk.STATUS_MAINTENANCE_MODE: 'Maintenance', Disk.STATUS_SPARE_DISK: 'Spare', Disk.STATUS_RECONSTRUCT: 'Reconstruct', Disk.STATUS_FREE: 'Free', } def disk_status_to_str(disk_status): return _bit_map_to_str(disk_status, _DISK_STATUS_CONV) _AG_INIT_TYPE_CONV = { AccessGroup.INIT_TYPE_UNKNOWN: 'Unknown', AccessGroup.INIT_TYPE_OTHER: 'Other', AccessGroup.INIT_TYPE_WWPN: 'WWPN', AccessGroup.INIT_TYPE_ISCSI_IQN: 'iSCSI', AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED: 'iSCSI/WWPN Mixed', } def ag_init_type_to_str(init_type): return _enum_type_to_str(init_type, _AG_INIT_TYPE_CONV) def ag_init_type_str_to_lsm(init_type_str): return _str_to_enum(init_type_str, _AG_INIT_TYPE_CONV) _TGT_PORT_TYPE_CONV = { TargetPort.TYPE_OTHER: 'Other', TargetPort.TYPE_FC: 'FC', TargetPort.TYPE_FCOE: 'FCoE', TargetPort.TYPE_ISCSI: 'iSCSI', } def tgt_port_type_to_str(port_type): return _enum_type_to_str(port_type, _TGT_PORT_TYPE_CONV) def disk_rpm_to_str(rpm): if rpm == '': return "No Support" if rpm == Disk.RPM_NO_SUPPORT: return "No Support" if rpm == Disk.RPM_UNKNOWN: return "Unknown" if rpm == Disk.RPM_NON_ROTATING_MEDIUM: return "Non-Rotating Medium" if rpm == Disk.RPM_ROTATING_UNKNOWN_SPEED: return "Rotating Medium Unknown Speed" return str(rpm) def disk_link_type_to_str(link_type): if link_type == '': return "No Support" return _enum_type_to_str(link_type, LocalDiskInfo._LINK_TYPE_MAP) def disk_health_status_to_str(health_status): if health_status == '': return "No Support" if health_status == Disk.HEALTH_STATUS_UNKNOWN: return "Unknown" if health_status == Disk.HEALTH_STATUS_FAIL: return "Failure" if health_status == Disk.HEALTH_STATUS_WARN: return "Warning" if health_status == Disk.HEALTH_STATUS_GOOD: return "Good" _BATTERY_TYPE_CONV = { Battery.TYPE_UNKNOWN: "Unknown", Battery.TYPE_OTHER: "Other", Battery.TYPE_CHEMICAL: "Chemical", Battery.TYPE_CAPACITOR: "Capacitor", } def battery_type_to_str(battery_type): return _enum_type_to_str(battery_type, _BATTERY_TYPE_CONV) _BATTERY_STATUS_CONV = { Battery.STATUS_UNKNOWN: "Unknown", Battery.STATUS_OTHER: "Other", Battery.STATUS_OK: "OK", Battery.STATUS_DISCHARGING: "Discharging", Battery.STATUS_CHARGING: "Charging", Battery.STATUS_LEARNING: "Learning", Battery.STATUS_DEGRADED: "Degraded", Battery.STATUS_ERROR: "Error", } def battery_status_to_str(battery_status): return _bit_map_to_str(battery_status, _BATTERY_STATUS_CONV) _DISK_LED_STATUS_CONV = { Disk.LED_STATUS_UNKNOWN: 'Unknown', Disk.LED_STATUS_IDENT_ON: 'IDENT_ON', Disk.LED_STATUS_IDENT_OFF: 'IDENT_OFF', Disk.LED_STATUS_IDENT_UNKNOWN: 'IDENT_UNKNOWN', Disk.LED_STATUS_FAULT_ON: 'FAULT_ON', Disk.LED_STATUS_FAULT_OFF: 'FAULT_OFF', Disk.LED_STATUS_FAULT_UNKNOWN: 'FAULT_UNKNOWN', } def disk_led_status_to_str(led_status): return _bit_map_to_str(led_status, _DISK_LED_STATUS_CONV) def disk_link_speed_to_str(link_speed): if link_speed == Disk.LINK_SPEED_UNKNOWN: return "Unknown" return "%.1f Gbps" % float(link_speed / 1000.0) class PlugData(object): def __init__(self, description, plugin_version): self.desc = description self.version = plugin_version class VolumeRAIDInfo(object): _RAID_TYPE_MAP = { Volume.RAID_TYPE_RAID0: 'RAID0', Volume.RAID_TYPE_RAID1: 'RAID1', Volume.RAID_TYPE_RAID3: 'RAID3', Volume.RAID_TYPE_RAID4: 'RAID4', Volume.RAID_TYPE_RAID5: 'RAID5', Volume.RAID_TYPE_RAID6: 'RAID6', Volume.RAID_TYPE_RAID10: 'RAID10', Volume.RAID_TYPE_RAID15: 'RAID15', Volume.RAID_TYPE_RAID16: 'RAID16', Volume.RAID_TYPE_RAID50: 'RAID50', Volume.RAID_TYPE_RAID60: 'RAID60', Volume.RAID_TYPE_RAID51: 'RAID51', Volume.RAID_TYPE_RAID61: 'RAID61', Volume.RAID_TYPE_JBOD: 'JBOD', Volume.RAID_TYPE_MIXED: 'MIXED', Volume.RAID_TYPE_OTHER: 'OTHER', Volume.RAID_TYPE_UNKNOWN: 'UNKNOWN', } VOL_CREATE_RAID_TYPES_STR = [ 'RAID0', 'RAID1', 'RAID5', 'RAID6', 'RAID10', 'RAID50', 'RAID60'] def __init__(self, vol_id, raid_type, strip_size, disk_count, min_io_size, opt_io_size): self.vol_id = vol_id self.raid_type = raid_type self.strip_size = strip_size self.disk_count = disk_count self.min_io_size = min_io_size self.opt_io_size = opt_io_size @staticmethod def raid_type_to_str(raid_type): return _enum_type_to_str(raid_type, VolumeRAIDInfo._RAID_TYPE_MAP) @staticmethod def raid_type_str_to_lsm(raid_type_str): return _str_to_enum(raid_type_str, VolumeRAIDInfo._RAID_TYPE_MAP) class PoolRAIDInfo(object): _MEMBER_TYPE_MAP = { Pool.MEMBER_TYPE_UNKNOWN: 'Unknown', Pool.MEMBER_TYPE_OTHER: 'Unknown', Pool.MEMBER_TYPE_POOL: 'Pool', Pool.MEMBER_TYPE_DISK: 'Disk', } def __init__(self, pool_id, raid_type, member_type, member_ids): self.pool_id = pool_id self.raid_type = raid_type self.member_type = member_type self.member_ids = member_ids @staticmethod def member_type_to_str(member_type): return _enum_type_to_str( member_type, PoolRAIDInfo._MEMBER_TYPE_MAP) class VcrCap(object): def __init__(self, system_id, raid_types, strip_sizes): self.system_id = system_id self.raid_types = raid_types self.strip_sizes = strip_sizes class LocalDiskInfo(object): _LINK_TYPE_MAP = { Disk.LINK_TYPE_NO_SUPPORT: "No Support", Disk.LINK_TYPE_UNKNOWN: "Unknown", Disk.LINK_TYPE_FC: "FC", Disk.LINK_TYPE_SSA: "SSA", Disk.LINK_TYPE_SBP: "SBP", Disk.LINK_TYPE_SRP: "SRP", Disk.LINK_TYPE_ISCSI: "iSCSI", Disk.LINK_TYPE_SAS: "SAS", Disk.LINK_TYPE_ADT: "ADT", Disk.LINK_TYPE_ATA: "PATA/SATA", Disk.LINK_TYPE_USB: "USB", Disk.LINK_TYPE_SOP: "SCSI over PCIE", Disk.LINK_TYPE_PCIE: "PCI-E", } def __init__(self, sd_path, vpd83, rpm, link_type, serial_num, led_status, link_speed, health_status): self.sd_path = sd_path self.vpd83 = vpd83 self.rpm = rpm self.link_type = link_type self.serial_num = serial_num self.led_status = led_status self.link_speed = link_speed self.health_status = health_status class VolumeRAMCacheInfo(object): _PHY_DISK_CACHE_STATUS_MAP = { Volume.PHYSICAL_DISK_CACHE_USE_DISK_SETTING: "Use Disk Setting", Volume.PHYSICAL_DISK_CACHE_ENABLED: "Enabled", Volume.PHYSICAL_DISK_CACHE_DISABLED: "Disabled", Volume.PHYSICAL_DISK_CACHE_UNKNOWN: "Unknown", } _W_CACHE_POLICY_MAP = { Volume.WRITE_CACHE_POLICY_UNKNOWN: "Unknown", Volume.WRITE_CACHE_POLICY_WRITE_BACK: "Write Back", Volume.WRITE_CACHE_POLICY_AUTO: "Auto", Volume.WRITE_CACHE_POLICY_WRITE_THROUGH: "Write Through", } _W_CACHE_STATUS_MAP = { Volume.WRITE_CACHE_STATUS_UNKNOWN: "Unknown", Volume.WRITE_CACHE_STATUS_WRITE_BACK: "Write Back", Volume.WRITE_CACHE_STATUS_WRITE_THROUGH: "Write Through", } _R_CACHE_POLICY_MAP = { Volume.READ_CACHE_POLICY_UNKNOWN: "Unknown", Volume.READ_CACHE_POLICY_ENABLED: "Enabled", Volume.READ_CACHE_POLICY_DISABLED: "Disabled", } _R_CACHE_STATUS_MAP = { Volume.READ_CACHE_STATUS_UNKNOWN: "Unknown", Volume.READ_CACHE_STATUS_ENABLED: "Enabled", Volume.READ_CACHE_STATUS_DISABLED: "Disabled", } def __init__(self, vol_id, write_cache_policy, write_cache_status, read_cache_policy, read_cache_status, phy_disk_cache): self.vol_id = vol_id self.write_cache_policy = write_cache_policy self.write_cache_status = write_cache_status self.read_cache_policy = read_cache_policy self.read_cache_status = read_cache_status self.phy_disk_cache = phy_disk_cache @staticmethod def phy_disk_cache_status_to_str(phy_disk_cache): return _enum_type_to_str( phy_disk_cache, VolumeRAMCacheInfo._PHY_DISK_CACHE_STATUS_MAP) @staticmethod def w_cache_policy_to_str(w_cache_p): return _enum_type_to_str( w_cache_p, VolumeRAMCacheInfo._W_CACHE_POLICY_MAP) @staticmethod def w_cache_status_to_str(w_cache_status): return _enum_type_to_str( w_cache_status, VolumeRAMCacheInfo._W_CACHE_STATUS_MAP) @staticmethod def r_cache_policy_to_str(r_cache_p): return _enum_type_to_str( r_cache_p, VolumeRAMCacheInfo._R_CACHE_POLICY_MAP) @staticmethod def r_cache_status_to_str(r_cache_status): return _enum_type_to_str( r_cache_status, VolumeRAMCacheInfo._R_CACHE_STATUS_MAP) class DisplayData(object): def __init__(self): pass DISPLAY_WAY_COLUMN = 0 DISPLAY_WAY_SCRIPT = 1 DISPLAY_WAY_DEFAULT = DISPLAY_WAY_COLUMN DEFAULT_SPLITTER = ' | ' VALUE_CONVERT = {} # lsm.System SYSTEM_HEADER = OrderedDict() SYSTEM_HEADER['id'] = 'ID' SYSTEM_HEADER['name'] = 'Name' SYSTEM_HEADER['status'] = 'Status' SYSTEM_HEADER['status_info'] = 'Info' SYSTEM_HEADER['fw_version'] = "FW Ver" SYSTEM_HEADER['mode'] = "Mode" SYSTEM_HEADER['read_cache_pct'] = "Read Cache Percentage" SYSTEM_COLUMN_SKIP_KEYS = [] # XXX_COLUMN_SKIP_KEYS contain a list of property should be skipped when # displaying in column way. SYSTEM_VALUE_CONV_ENUM = { 'status': system_status_to_str, 'mode': system_mode_to_str, } SYSTEM_VALUE_CONV_HUMAN = [] VALUE_CONVERT[System] = { 'headers': SYSTEM_HEADER, 'column_skip_keys': SYSTEM_COLUMN_SKIP_KEYS, 'value_conv_enum': SYSTEM_VALUE_CONV_ENUM, 'value_conv_human': SYSTEM_VALUE_CONV_HUMAN, } PLUG_DATA_HEADER = OrderedDict() PLUG_DATA_HEADER['desc'] = 'Description' PLUG_DATA_HEADER['version'] = 'Version' PLUG_DATA_COLUMN_SKIP_KEYS = [] PLUG_DATA_VALUE_CONV_ENUM = {} PLUG_DATA_VALUE_CONV_HUMAN = [] VALUE_CONVERT[PlugData] = { 'headers': PLUG_DATA_HEADER, 'column_skip_keys': PLUG_DATA_COLUMN_SKIP_KEYS, 'value_conv_enum': PLUG_DATA_VALUE_CONV_ENUM, 'value_conv_human': PLUG_DATA_VALUE_CONV_HUMAN, } # lsm.Pool POOL_HEADER = OrderedDict() POOL_HEADER['id'] = 'ID' POOL_HEADER['name'] = 'Name' POOL_HEADER['element_type'] = 'Element Type' POOL_HEADER['unsupported_actions'] = 'Does not support' POOL_HEADER['total_space'] = 'Total Space' POOL_HEADER['free_space'] = 'Free Space' POOL_HEADER['status'] = 'Status' POOL_HEADER['status_info'] = 'Info' POOL_HEADER['system_id'] = 'System ID' POOL_COLUMN_SKIP_KEYS = ['unsupported_actions'] POOL_VALUE_CONV_ENUM = { 'status': pool_status_to_str, 'element_type': pool_element_type_to_str, 'unsupported_actions': pool_unsupported_actions_to_str } POOL_VALUE_CONV_HUMAN = ['total_space', 'free_space'] VALUE_CONVERT[Pool] = { 'headers': POOL_HEADER, 'column_skip_keys': POOL_COLUMN_SKIP_KEYS, 'value_conv_enum': POOL_VALUE_CONV_ENUM, 'value_conv_human': POOL_VALUE_CONV_HUMAN, } # lsm.Volume VOL_HEADER = OrderedDict() VOL_HEADER['id'] = 'ID' VOL_HEADER['name'] = 'Name' VOL_HEADER['vpd83'] = 'SCSI VPD 0x83' VOL_HEADER['block_size'] = 'Block Size' VOL_HEADER['num_of_blocks'] = 'Block Count' VOL_HEADER['size_bytes'] = 'Size' VOL_HEADER['admin_state'] = 'Disabled' VOL_HEADER['pool_id'] = 'Pool ID' VOL_HEADER['system_id'] = 'System ID' VOL_HEADER['sd_paths'] = 'Disk Paths' # This is appended by cmdline.py VOL_COLUMN_SKIP_KEYS = ['block_size', 'num_of_blocks'] VOL_VALUE_CONV_ENUM = { 'admin_state': vol_admin_state_to_str } VOL_VALUE_CONV_HUMAN = ['size_bytes', 'block_size'] VALUE_CONVERT[Volume] = { 'headers': VOL_HEADER, 'column_skip_keys': VOL_COLUMN_SKIP_KEYS, 'value_conv_enum': VOL_VALUE_CONV_ENUM, 'value_conv_human': VOL_VALUE_CONV_HUMAN, } # lsm.Disk DISK_HEADER = OrderedDict() DISK_HEADER['id'] = 'ID' DISK_HEADER['name'] = 'Name' DISK_HEADER['disk_type'] = 'Type' DISK_HEADER['block_size'] = 'Block Size' DISK_HEADER['num_of_blocks'] = 'Block Count' DISK_HEADER['size_bytes'] = 'Size' DISK_HEADER['status'] = 'Status' DISK_HEADER['system_id'] = 'System ID' DISK_HEADER['vpd83'] = 'SCSI VPD 0x83' DISK_HEADER['sd_paths'] = 'Disk Paths' # This is appended by cmdline.py DISK_HEADER['rpm'] = 'Revolutions Per Minute' DISK_HEADER['link_type'] = 'Link Type' DISK_HEADER['location'] = 'Location' DISK_COLUMN_SKIP_KEYS = ['block_size', 'num_of_blocks', 'location'] DISK_VALUE_CONV_ENUM = { 'status': disk_status_to_str, 'disk_type': disk_type_to_str, 'rpm': disk_rpm_to_str, 'link_type': disk_link_type_to_str, } DISK_VALUE_CONV_HUMAN = ['size_bytes', 'block_size'] VALUE_CONVERT[Disk] = { 'headers': DISK_HEADER, 'column_skip_keys': DISK_COLUMN_SKIP_KEYS, 'value_conv_enum': DISK_VALUE_CONV_ENUM, 'value_conv_human': DISK_VALUE_CONV_HUMAN, } # lsm.AccessGroup AG_HEADER = OrderedDict() AG_HEADER['id'] = 'ID' AG_HEADER['name'] = 'Name' AG_HEADER['init_ids'] = 'Initiator IDs' AG_HEADER['init_type'] = 'Type' AG_HEADER['system_id'] = 'System ID' AG_COLUMN_SKIP_KEYS = ['init_type'] AG_VALUE_CONV_ENUM = { 'init_type': ag_init_type_to_str, } AG_VALUE_CONV_HUMAN = [] VALUE_CONVERT[AccessGroup] = { 'headers': AG_HEADER, 'column_skip_keys': AG_COLUMN_SKIP_KEYS, 'value_conv_enum': AG_VALUE_CONV_ENUM, 'value_conv_human': AG_VALUE_CONV_HUMAN, } # lsm.FileSystem FS_HEADER = OrderedDict() FS_HEADER['id'] = 'ID' FS_HEADER['name'] = 'Name' FS_HEADER['total_space'] = 'Total Space' FS_HEADER['free_space'] = 'Free Space' FS_HEADER['pool_id'] = 'Pool ID' FS_HEADER['system_id'] = 'System ID' FS_COLUMN_SKIP_KEYS = [] FS_VALUE_CONV_ENUM = { } FS_VALUE_CONV_HUMAN = ['total_space', 'free_space'] VALUE_CONVERT[FileSystem] = { 'headers': FS_HEADER, 'column_skip_keys': FS_COLUMN_SKIP_KEYS, 'value_conv_enum': FS_VALUE_CONV_ENUM, 'value_conv_human': FS_VALUE_CONV_HUMAN, } # lsm.FsSnapshot FS_SNAP_HEADER = OrderedDict() FS_SNAP_HEADER['id'] = 'ID' FS_SNAP_HEADER['name'] = 'Name' FS_SNAP_HEADER['ts'] = 'Time Stamp' FS_SNAP_COLUMN_SKIP_KEYS = [] FS_SNAP_VALUE_CONV_ENUM = { 'ts': datetime.fromtimestamp } FS_SNAP_VALUE_CONV_HUMAN = [] VALUE_CONVERT[FsSnapshot] = { 'headers': FS_SNAP_HEADER, 'column_skip_keys': FS_SNAP_COLUMN_SKIP_KEYS, 'value_conv_enum': FS_SNAP_VALUE_CONV_ENUM, 'value_conv_human': FS_SNAP_VALUE_CONV_HUMAN, } # lsm.NfsExport NFS_EXPORT_HEADER = OrderedDict() NFS_EXPORT_HEADER['id'] = 'ID' NFS_EXPORT_HEADER['fs_id'] = 'FileSystem ID' NFS_EXPORT_HEADER['export_path'] = 'Export Path' NFS_EXPORT_HEADER['auth'] = 'Auth Type' NFS_EXPORT_HEADER['root'] = 'Root Hosts' NFS_EXPORT_HEADER['rw'] = 'RW Hosts' NFS_EXPORT_HEADER['ro'] = 'RO Hosts' NFS_EXPORT_HEADER['anonuid'] = 'Anonymous UID' NFS_EXPORT_HEADER['anongid'] = 'Anonymous GID' NFS_EXPORT_HEADER['options'] = 'Options' NFS_EXPORT_COLUMN_SKIP_KEYS = ['anonuid', 'anongid', 'auth'] NFS_EXPORT_VALUE_CONV_ENUM = {} NFS_EXPORT_VALUE_CONV_HUMAN = [] VALUE_CONVERT[NfsExport] = { 'headers': NFS_EXPORT_HEADER, 'column_skip_keys': NFS_EXPORT_COLUMN_SKIP_KEYS, 'value_conv_enum': NFS_EXPORT_VALUE_CONV_ENUM, 'value_conv_human': NFS_EXPORT_VALUE_CONV_HUMAN, } # lsm.TargetPort TGT_PORT_HEADER = OrderedDict() TGT_PORT_HEADER['id'] = 'ID' TGT_PORT_HEADER['port_type'] = 'Type' TGT_PORT_HEADER['physical_name'] = 'Physical Name' TGT_PORT_HEADER['service_address'] = 'Address' TGT_PORT_HEADER['network_address'] = 'Network Address' TGT_PORT_HEADER['physical_address'] = 'Physical Address' TGT_PORT_HEADER['system_id'] = 'System ID' TGT_PORT_COLUMN_SKIP_KEYS = ['physical_address', 'physical_name'] TGT_PORT_VALUE_CONV_ENUM = { 'port_type': tgt_port_type_to_str, } TGT_PORT_VALUE_CONV_HUMAN = [] VALUE_CONVERT[TargetPort] = { 'headers': TGT_PORT_HEADER, 'column_skip_keys': TGT_PORT_COLUMN_SKIP_KEYS, 'value_conv_enum': TGT_PORT_VALUE_CONV_ENUM, 'value_conv_human': TGT_PORT_VALUE_CONV_HUMAN, } VOL_RAID_INFO_HEADER = OrderedDict() VOL_RAID_INFO_HEADER['vol_id'] = 'Volume ID' VOL_RAID_INFO_HEADER['raid_type'] = 'RAID Type' VOL_RAID_INFO_HEADER['strip_size'] = 'Strip Size' VOL_RAID_INFO_HEADER['disk_count'] = 'Disk Count' VOL_RAID_INFO_HEADER['min_io_size'] = 'Minimum I/O Size' VOL_RAID_INFO_HEADER['opt_io_size'] = 'Optimal I/O Size' VOL_RAID_INFO_COLUMN_SKIP_KEYS = [] VOL_RAID_INFO_VALUE_CONV_ENUM = { 'raid_type': VolumeRAIDInfo.raid_type_to_str, } VOL_RAID_INFO_VALUE_CONV_HUMAN = [ 'strip_size', 'min_io_size', 'opt_io_size'] VALUE_CONVERT[VolumeRAIDInfo] = { 'headers': VOL_RAID_INFO_HEADER, 'column_skip_keys': VOL_RAID_INFO_COLUMN_SKIP_KEYS, 'value_conv_enum': VOL_RAID_INFO_VALUE_CONV_ENUM, 'value_conv_human': VOL_RAID_INFO_VALUE_CONV_HUMAN, } POOL_RAID_INFO_HEADER = OrderedDict() POOL_RAID_INFO_HEADER['pool_id'] = 'Pool ID' POOL_RAID_INFO_HEADER['raid_type'] = 'RAID Type' POOL_RAID_INFO_HEADER['member_type'] = 'Member Type' POOL_RAID_INFO_HEADER['member_ids'] = 'Member IDs' POOL_RAID_INFO_COLUMN_SKIP_KEYS = [] POOL_RAID_INFO_VALUE_CONV_ENUM = { 'raid_type': VolumeRAIDInfo.raid_type_to_str, 'member_type': PoolRAIDInfo.member_type_to_str, } POOL_RAID_INFO_VALUE_CONV_HUMAN = [] VALUE_CONVERT[PoolRAIDInfo] = { 'headers': POOL_RAID_INFO_HEADER, 'column_skip_keys': POOL_RAID_INFO_COLUMN_SKIP_KEYS, 'value_conv_enum': POOL_RAID_INFO_VALUE_CONV_ENUM, 'value_conv_human': POOL_RAID_INFO_VALUE_CONV_HUMAN, } VCR_CAP_HEADER = OrderedDict() VCR_CAP_HEADER['system_id'] = 'System ID' VCR_CAP_HEADER['raid_types'] = 'Supported RAID Types' VCR_CAP_HEADER['strip_sizes'] = 'Supported Strip Sizes' VCR_CAP_COLUMN_SKIP_KEYS = [] VCR_CAP_VALUE_CONV_ENUM = { 'raid_types': lambda i: [VolumeRAIDInfo.raid_type_to_str(x) for x in i] } VCR_CAP_VALUE_CONV_HUMAN = ['strip_sizes'] VALUE_CONVERT[VcrCap] = { 'headers': VCR_CAP_HEADER, 'column_skip_keys': VCR_CAP_COLUMN_SKIP_KEYS, 'value_conv_enum': VCR_CAP_VALUE_CONV_ENUM, 'value_conv_human': VCR_CAP_VALUE_CONV_HUMAN, } LOCAL_DISK_HEADER = OrderedDict() LOCAL_DISK_HEADER['sd_path'] = 'Path' LOCAL_DISK_HEADER['vpd83'] = 'SCSI VPD 0x83' LOCAL_DISK_HEADER['rpm'] = 'Revolutions Per Minute' LOCAL_DISK_HEADER['link_type'] = 'Link Type' LOCAL_DISK_HEADER['serial_num'] = 'Serial Number' LOCAL_DISK_HEADER['led_status'] = 'LED Status' LOCAL_DISK_HEADER['link_speed'] = 'Link Speed' LOCAL_DISK_HEADER['health_status'] = 'Health Status' LOCAL_DISK_COLUMN_SKIP_KEYS = ['rpm', 'led_status', 'link_speed'] LOCAL_DISK_VALUE_CONV_ENUM = { 'rpm': disk_rpm_to_str, 'link_type': disk_link_type_to_str, 'led_status': disk_led_status_to_str, 'link_speed': disk_link_speed_to_str, 'health_status': disk_health_status_to_str, } LOCAL_DISK_VALUE_CONV_HUMAN = [] VALUE_CONVERT[LocalDiskInfo] = { 'headers': LOCAL_DISK_HEADER, 'column_skip_keys': LOCAL_DISK_COLUMN_SKIP_KEYS, 'value_conv_enum': LOCAL_DISK_VALUE_CONV_ENUM, 'value_conv_human': LOCAL_DISK_VALUE_CONV_HUMAN, } BATTERY_HEADER = OrderedDict() BATTERY_HEADER['id'] = 'ID' BATTERY_HEADER['name'] = 'Name' BATTERY_HEADER['type'] = 'Type' BATTERY_HEADER['status'] = 'Status' BATTERY_HEADER['system_id'] = 'System ID' BATTERY_COLUMN_SKIP_KEYS = [] BATTERY_VALUE_CONV_ENUM = { 'type': battery_type_to_str, 'status': battery_status_to_str, } BATTERY_VALUE_CONV_HUMAN = [''] VALUE_CONVERT[Battery] = { 'headers': BATTERY_HEADER, 'column_skip_keys': BATTERY_COLUMN_SKIP_KEYS, 'value_conv_enum': BATTERY_VALUE_CONV_ENUM, 'value_conv_human': BATTERY_VALUE_CONV_HUMAN, } VOL_CACHE_INFO_HEADER = OrderedDict() VOL_CACHE_INFO_HEADER['vol_id'] = 'Volume ID' VOL_CACHE_INFO_HEADER['write_cache_policy'] = 'Write Cache Policy' VOL_CACHE_INFO_HEADER['write_cache_status'] = 'Write Cache' VOL_CACHE_INFO_HEADER['read_cache_policy'] = 'Read Cache Policy' VOL_CACHE_INFO_HEADER['read_cache_status'] = 'Read Cache' VOL_CACHE_INFO_HEADER['phy_disk_cache'] = 'Physical Disk Cache' VOL_CACHE_INFO_COLUMN_SKIP_KEYS = [] VOL_CACHE_INFO_VALUE_CONV_ENUM = { 'write_cache_policy': VolumeRAMCacheInfo.w_cache_policy_to_str, 'write_cache_status': VolumeRAMCacheInfo.w_cache_status_to_str, 'read_cache_policy': VolumeRAMCacheInfo.r_cache_policy_to_str, 'read_cache_status': VolumeRAMCacheInfo.r_cache_status_to_str, 'phy_disk_cache': VolumeRAMCacheInfo.phy_disk_cache_status_to_str, } VOL_CACHE_INFO_VALUE_CONV_HUMAN = [] VALUE_CONVERT[VolumeRAMCacheInfo] = { 'headers': VOL_CACHE_INFO_HEADER, 'column_skip_keys': VOL_CACHE_INFO_COLUMN_SKIP_KEYS, 'value_conv_enum': VOL_CACHE_INFO_VALUE_CONV_ENUM, 'value_conv_human': VOL_CACHE_INFO_VALUE_CONV_HUMAN, } @staticmethod def _get_man_pro_value(obj, key, value_conv_enum, value_conv_human, flag_human, flag_enum): try: value = getattr(obj, key) except LsmError as lsm_err: if lsm_err.code == ErrorNumber.NO_SUPPORT: value = '' else: raise lsm_err if not flag_enum: if key in list(value_conv_enum.keys()): value = value_conv_enum[key](value) if flag_human: if key in value_conv_human: if type(value) is list: value = list(size_bytes_2_size_human(s) for s in value) else: value = size_bytes_2_size_human(value) return value @staticmethod def _find_max_width(two_d_list, column_index): max_width = 1 for row_index in range(0, len(two_d_list)): row_data = two_d_list[row_index] if len(row_data[column_index]) > max_width: max_width = len(row_data[column_index]) return max_width @staticmethod def _data_dict_gen(obj, flag_human, flag_enum, display_way, extra_properties=None, flag_dsp_all_data=False): data_dict = OrderedDict() value_convert = DisplayData.VALUE_CONVERT[type(obj)] headers = value_convert['headers'] value_conv_enum = value_convert['value_conv_enum'] value_conv_human = value_convert['value_conv_human'] if flag_dsp_all_data: display_way = DisplayData.DISPLAY_WAY_SCRIPT display_keys = [] if display_way == DisplayData.DISPLAY_WAY_COLUMN: for key_name in list(headers.keys()): if key_name not in value_convert['column_skip_keys']: display_keys.append(key_name) elif display_way == DisplayData.DISPLAY_WAY_SCRIPT: display_keys = list(headers.keys()) if extra_properties: for extra_key_name in extra_properties: if extra_key_name not in display_keys: display_keys.append(extra_key_name) for key in display_keys: key_str = headers[key] value = DisplayData._get_man_pro_value( obj, key, value_conv_enum, value_conv_human, flag_human, flag_enum) data_dict[key_str] = value return data_dict @staticmethod def display_data(objs, display_way=None, flag_human=True, flag_enum=False, extra_properties=None, splitter=None, flag_with_header=True, flag_dsp_all_data=False): if len(objs) == 0: return None if display_way is None: display_way = DisplayData.DISPLAY_WAY_DEFAULT if splitter is None: splitter = DisplayData.DEFAULT_SPLITTER data_dict_list = [] if type(objs[0]) in list(DisplayData.VALUE_CONVERT.keys()): for obj in objs: data_dict = DisplayData._data_dict_gen( obj, flag_human, flag_enum, display_way, extra_properties, flag_dsp_all_data) data_dict_list.extend([data_dict]) else: return None if display_way == DisplayData.DISPLAY_WAY_SCRIPT: DisplayData.display_data_script_way(data_dict_list, splitter) elif display_way == DisplayData.DISPLAY_WAY_COLUMN: DisplayData._display_data_column_way( data_dict_list, splitter, flag_with_header) return True @staticmethod def display_data_script_way(data_dict_list, splitter): key_column_width = 1 value_column_width = 1 for data_dict in data_dict_list: for key_name in list(data_dict.keys()): # find the max column width of key cur_key_width = len(key_name) if cur_key_width > key_column_width: key_column_width = cur_key_width # find the max column width of value cur_value = data_dict[key_name] if isinstance(cur_value, list): if len(cur_value) == 0: continue cur_value_width = len(str(cur_value[0])) else: cur_value_width = len(str(cur_value)) if cur_value_width > value_column_width: value_column_width = cur_value_width row_format = '%%-%ds%s%%-%ds' % (key_column_width, splitter, value_column_width) sub_row_format = '%s%s%%-%ds' % (' ' * key_column_width, splitter, value_column_width) obj_splitter = '%s%s%s' % ('-' * key_column_width, '-' * len(splitter), '-' * value_column_width) for data_dict in data_dict_list: out(obj_splitter) for key_name in data_dict: value = data_dict[key_name] if isinstance(value, list): flag_first_data = True for sub_value in value: if flag_first_data: out(row_format % (key_name, str(sub_value))) flag_first_data = False else: out(sub_row_format % str(sub_value)) else: out(row_format % (key_name, str(value))) out(obj_splitter) @staticmethod def _display_data_column_way(data_dict_list, splitter, flag_with_header): if len(data_dict_list) == 0: return two_d_list = [] item_count = len(list(data_dict_list[0].keys())) # determine how many lines we will print row_width = 0 for data_dict in data_dict_list: cur_max_wd = 0 for key_name in list(data_dict.keys()): if isinstance(data_dict[key_name], list): cur_row_width = len(data_dict[key_name]) if cur_row_width > cur_max_wd: cur_max_wd = cur_row_width else: pass if cur_max_wd == 0: cur_max_wd = 1 row_width += cur_max_wd if flag_with_header: # first line for header row_width += 1 # init 2D list for raw in range(0, row_width): new = [] for column in range(0, item_count): new.append('') two_d_list.append(new) # header current_row_num = -1 if flag_with_header: two_d_list[0] = list(data_dict_list[0].keys()) current_row_num = 0 # Fill the 2D list with data_dict_list for data_dict in data_dict_list: current_row_num += 1 save_row_num = current_row_num values = list(data_dict.values()) for index in range(0, len(values)): value = values[index] if isinstance(value, list): for sub_index in range(0, len(value)): tmp_row_num = save_row_num + sub_index two_d_list[tmp_row_num][index] = str(value[sub_index]) if save_row_num + len(value) > current_row_num: current_row_num = save_row_num + len(value) - 1 else: two_d_list[save_row_num][index] = str(value) # display two_list row_formats = [] header_splitter = '' for column_index in range(0, len(two_d_list[0])): max_width = DisplayData._find_max_width(two_d_list, column_index) row_formats.extend(['%%-%ds' % max_width]) header_splitter += '-' * max_width if column_index != (len(two_d_list[0]) - 1): header_splitter += '-' * len(splitter) row_format = splitter.join(row_formats) for row_index in range(0, len(two_d_list)): out(row_format % tuple(two_d_list[row_index])) if row_index == 0 and flag_with_header: out(header_splitter) lsmcli/cmdline.py000064400000216125147576505410010041 0ustar00# Copyright (C) 2012-2016 Red Hat, Inc. # (C) Copyright 2017 Hewlett Packard Enterprise Development LP # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: tasleson # Gris Ge import os import sys import getpass import re import time import tty import termios from argparse import ArgumentParser, ArgumentTypeError from argparse import RawTextHelpFormatter import six from lsm import (Client, Pool, VERSION, LsmError, Disk, Volume, JobStatus, ErrorNumber, BlockRange, uri_parse, Proxy, size_human_2_size_bytes, AccessGroup, FileSystem, NfsExport, TargetPort, LocalDisk, Battery) from lsm.lsmcli.data_display import ( DisplayData, PlugData, out, vol_provision_str_to_type, vol_rep_type_str_to_type, VolumeRAIDInfo, PoolRAIDInfo, VcrCap, LocalDiskInfo, VolumeRAMCacheInfo) _CONNECTION_FREE_COMMANDS = ['local-disk-list', 'local-disk-ident-led-on', 'local-disk-ident-led-off', 'local-disk-fault-led-on', 'local-disk-fault-led-off'] if six.PY3: long = int try: from collections import OrderedDict except ImportError: # python 2.6 or earlier, use backport # noinspection PyUnresolvedReferences from ordereddict import OrderedDict # Wraps the invocation to the command line # @param c Object to invoke calls on (optional) def cmd_line_wrapper(c=None): """ Common command line code, called. """ err_exit = 0 cli = None try: cli = CmdLine() cli.process(c) except ArgError as ae: sys.stderr.write(str(ae)) sys.stderr.flush() err_exit = 2 except LsmError as le: sys.stderr.write(str(le) + "\n") sys.stderr.flush() if le.code == ErrorNumber.PERMISSION_DENIED: err_exit = 13 # common error code for EACCES else: err_exit = 4 except KeyboardInterrupt: err_exit = 1 except SystemExit as se: # argparse raises a SystemExit err_exit = se.code except: import traceback traceback.print_exc(file=sys.stdout) # We get *any* other exception don't return a successful error code err_exit = 2 finally: # Regardless of what happens, we will try to close the connection if # possible to allow the plugin to clean up gracefully. if cli: try: # This will exit if are successful cli.shutdown(err_exit) except Exception: pass sys.exit(err_exit) # Get a character from stdin without needing a return key pressed. # Returns the character pressed def getch(): fd = sys.stdin.fileno() prev = termios.tcgetattr(fd) try: tty.setraw(sys.stdin.fileno()) ch = sys.stdin.read(1) finally: termios.tcsetattr(fd, termios.TCSADRAIN, prev) return ch def parse_convert_init(init_id): """ If init_id is a WWPN, convert it into LSM standard version: (?:[0-9a-f]{2}:){7}[0-9a-f]{2} Return (converted_init_id, lsm_init_type) """ valid, converted_init_type, converted_init_id = \ AccessGroup.initiator_id_verify(init_id) if valid: return converted_init_id, converted_init_type raise ArgError("--init \"%s\" is not a valid WWPN or iSCSI IQN" % init_id) def _check_init(init_id): """ Call back from validating an initiator :param init_id: Initiator to validate :return: Value of initiator or raises an exception """ valid, _, converted_init_id = \ AccessGroup.initiator_id_verify(init_id) if valid: return converted_init_id raise ArgumentTypeError("\"%s\" is invalid WWPN or iSCSI IQN" % init_id) def _check_positive_integer(num): """ Call back for validating a positive integer :param num: Number string to check :return: Numeric value, else exception """ try: rc = long(num, 10) if rc < 0: raise ArgumentTypeError( "invalid: require positive integer value '%d'" % rc) return rc except ValueError: raise ArgumentTypeError( "invalid: not a positive integer value '%s'" % num) _CHILD_OPTION_DST_PREFIX = 'child_' def _upper(s): return s.upper() def _valid_ip4_address(address): """ Check if a string represents a valid ip4 address :param address: String representing address :return: True if valid address, else false """ if not address: return False parts = address.split('.') if len(parts) != 4: return False if '/' in address: return False for i in parts: if not 0 < len(i) <= 3: return False if len(i) > 1 and i[0] == '0': return False try: if int(i, 10) > 255: return False except ValueError: return False return True def _valid_ip6_address(address): """ Check if a string represents a valid ipv6 address :param address: String representing address :return: True if valid address, else false """ allowed = 'ABCDEFabcdef0123456789:' has_zeros = False if not address: return False if '/' in address: return False if len(address.split("::")) > 2: return False parts = address.split(':') if len(parts) < 3 or len(parts) > 9: return False # Check for ipv4 suffix, validate and remove while adding padding for # addl. checks. if '.' in parts[-1]: if not _valid_ip4_address(parts.pop()): print("Not valid ipv suffix") return False parts.extend(['0', '0']) if '::' in address: parts = [p for p in parts if p != ''] # Add one segment of zero to catch full address with extra ':' parts.append('0') has_zeros = True if (has_zeros and len(parts) <= 8) or len(parts) == 8: return all(len(x) <= 4 for x in parts) and \ all(x in allowed for x in "".join(parts)) return False def _is_valid_network_name(ip_hn): """ Checks to see if the supplied string is a valid ip4/6 or hostname :param ip_hn: String representing address user inputted :return: True if valid IP address or hostname """ allowed = re.compile("(?!-)[A-Z0-9-]{1,63}(? 255: return False # A hostname cannot exist with only digits per spec. as that is confusing # for distinguishing IP from hostname if digits_only.match(ip_hn): return False if ip_hn[-1] == ".": ip_hn = ip_hn[:-1] # Yes, absolute hostnames have a trailing dot! return all(allowed.match(x) for x in ip_hn.split(".")) def _add_common_options(arg_parser, is_child=False): """ As https://bugs.python.org/issue23058 indicate, argument parser should not have subparser sharing the same argument and destination. For subparser, we add common options as 'child_xxx' destination. For default value, False is the only allowed default value in root. """ prefix = '' if is_child: prefix = _CHILD_OPTION_DST_PREFIX arg_parser.add_argument( '-v', '--version', action='version', version="%s %s" % (sys.argv[0], VERSION)) arg_parser.add_argument( '-u', '--uri', action="store", type=str, metavar='', dest="%suri" % prefix, help='Uniform resource identifier (env LSMCLI_URI)') arg_parser.add_argument( '-P', '--prompt', action="store_true", dest="%sprompt" % prefix, help='Prompt for password (env LSMCLI_PASSWORD)') arg_parser.add_argument( '-H', '--human', action="store_true", dest="%shuman" % prefix, help='Print sizes in human readable format\n' '(e.g., MiB, GiB, TiB)') arg_parser.add_argument( '-t', '--terse', action="store", dest="%ssep" % prefix, metavar='', help='Print output in terse form with "SEP" ' 'as a record separator') arg_parser.add_argument( '-e', '--enum', action="store_true", dest="%senum" % prefix, default=False, help='Display enumerated types as numbers instead of text') arg_parser.add_argument( '-f', '--force', action="store_true", dest="%sforce" % prefix, default=False, help='Bypass confirmation prompt for data loss operations') arg_parser.add_argument( '-w', '--wait', action="store", dest="%swait" % prefix, help="Command timeout value in ms (default = 30s)", type=_check_positive_integer) arg_parser.add_argument( '--header', action="store_true", dest="%sheader" % prefix, help='Include the header with terse') arg_parser.add_argument( '-b', action="store_true", dest="%s_async" % prefix, default=False, help='Run the command async. Instead of waiting for completion.\n ' 'Command will exit(7) and job id written to stdout.') arg_parser.add_argument( '-s', '--script', action="store_true", dest="%sscript" % prefix, default=False, help='Displaying data in script friendly way with ' 'additional information(if exists)') if is_child: default_dict = dict() default_dict['%swait' % prefix] = 30000 arg_parser.set_defaults(**default_dict) def _add_sd_paths(lsm_obj): lsm_obj.sd_paths = [] try: if len(lsm_obj.vpd83) > 0: lsm_obj.sd_paths = LocalDisk.vpd83_search(lsm_obj.vpd83) except LsmError as lsm_err: if lsm_err.code != ErrorNumber.NO_SUPPORT: raise return lsm_obj # This class represents a command line argument error class ArgError(Exception): def __init__(self, message, *args, **kwargs): """ Class represents an error. """ Exception.__init__(self, *args, **kwargs) self.msg = message def __str__(self): return "%s: error: %s\n" % (os.path.basename(sys.argv[0]), self.msg) # Finds an item based on the id. Each list item requires a member "id" # @param l list to search # @param the_id the id to match # @param friendly_name - name to put in the exception saying what we # couldn't find def _get_item(l, the_id, friendly_name='item', raise_error=True): for item in l: if item.id == the_id: return item if raise_error: raise ArgError('%s with ID %s not found!' % (friendly_name, the_id)) else: return None def _check_network_host(addr): """ Custom value checker for hostname/IP address :param addr: :return: """ valid = _is_valid_network_name(addr) if valid: return addr raise ArgumentTypeError("%s is invalid IP or hostname" % addr) list_choices = ['VOLUMES', 'POOLS', 'FS', 'SNAPSHOTS', 'EXPORTS', "NFS_CLIENT_AUTH", 'ACCESS_GROUPS', 'SYSTEMS', 'DISKS', 'PLUGINS', 'TARGET_PORTS', 'BATTERIES'] provision_types = ('DEFAULT', 'THIN', 'FULL') provision_help = "provisioning type: " + ", ".join(provision_types) replicate_types = ('CLONE', 'COPY', 'MIRROR_ASYNC', 'MIRROR_SYNC') replicate_help = "replication type: " + ", ".join(replicate_types) policy_types = ['ENABLE', 'DISABLE'] policy_help = 'Policy: ' + ', '.join(policy_types) policy_opt = dict(name="--policy", metavar='', help=policy_help, choices=policy_types, type=_upper) write_cache_policy_types = ['WB', 'AUTO', 'WT'] write_cache_policy_help = 'Write cache polices: ' + \ ', '.join(write_cache_policy_types) + \ ' which stand for "write back", "auto", ' + \ '"write through"' write_cache_policy_opt = dict(name="--policy", metavar='', help=write_cache_policy_help, choices=write_cache_policy_types, type=_upper) size_help = 'Can use B, KiB, MiB, GiB, TiB, PiB postfix (IEC sizing)' sys_id_opt = dict(name='--sys', metavar='', help='System ID') sys_id_filter_opt = sys_id_opt.copy() sys_id_filter_opt['help'] = \ 'Search by System ID. Only supported for: \n' \ '(VOLUMES, POOLS, FS, DISKS, ACCESS_GROUPS,\n' \ 'TARGET_PORTS, BATTERIES)' pool_id_opt = dict(name='--pool', metavar='', help='Pool ID') pool_id_filter_opt = pool_id_opt.copy() pool_id_filter_opt['help'] = \ 'Search by Pool ID. Only supported for:\n' \ '(VOLUMES, POOLS, FS)' vol_id_opt = dict(name='--vol', metavar='', help='Volume ID') vol_id_filter_opt = vol_id_opt.copy() vol_id_filter_opt['help'] = \ 'Search by Volume ID. Only supported for:\n' \ '(VOLUMES, ACCESS_GROUPS)' fs_id_opt = dict(name='--fs', metavar='', help='File System ID') fs_id_filter_opt = fs_id_opt.copy() fs_id_filter_opt['help'] = \ 'Search by FS ID. Only supported for:\n' \ '(FS, SNAPSHOTS, EXPORTS)' ag_id_opt = dict(name='--ag', metavar='', help='Access Group ID') ag_id_filter_opt = ag_id_opt.copy() ag_id_filter_opt['help'] = \ 'Search by Access Group ID. Only supported for:\n' \ '(ACCESS_GROUPS, VOLUMES)' init_id_opt = dict(name='--init', metavar='', help='Initiator ID', type=_check_init) snap_id_opt = dict(name='--snap', metavar='', help='Snapshot ID') export_id_opt = dict(name='--export', metavar='', help='Export ID') nfs_export_id_filter_opt = dict( name='--nfs-export', metavar='', help= 'Search by NFS Export ID. Only supported for:\n' '(EXPORTS)') disk_id_filter_opt = dict(name='--disk', metavar='', help='Search by Disk ID. Only supported for:\n' '(DISKS)') size_opt = dict(name='--size', metavar='', help=size_help) tgt_id_filter_opt = dict(name="--tgt", metavar='', help="Search by target port ID. Only supported for:\n" "(TARGET_PORTS)") local_disk_path_opt = dict(name='--path', help="Local disk path", metavar='') cmds = ( dict( name='list', help="List records of different types", args=[ dict(name='--type', help="List records of type:\n " + "\n ".join(list_choices) + "\n\nWhen listing SNAPSHOTS, it requires --fs .", metavar='', choices=list_choices, type=_upper), ], optional=[ dict(sys_id_filter_opt), dict(pool_id_filter_opt), dict(vol_id_filter_opt), dict(disk_id_filter_opt), dict(ag_id_filter_opt), dict(fs_id_filter_opt), dict(nfs_export_id_filter_opt), dict(tgt_id_filter_opt), ], ), dict( name='job-status', help='Retrieve information about a job', args=[ dict(name="--job", metavar="", help='job status id'), ], ), dict( name='capabilities', help='Retrieves array capabilities', args=[ dict(sys_id_opt), ], ), dict( name='plugin-info', help='Retrieves plugin description and version', ), dict( name='volume-create', help='Creates a volume (logical unit)', args=[ dict(name="--name", help='volume name', metavar=''), dict(size_opt), dict(pool_id_opt), ], optional=[ dict(name="--provisioning", help=provision_help, default='DEFAULT', choices=provision_types, type=_upper), ], ), dict( name='volume-raid-create', help='Creates a RAIDed volume on hardware RAID', args=[ dict(name="--name", help='volume name', metavar=''), dict(name="--disk", metavar='', help='Free disks for new RAIDed volume.\n' 'This is repeatable argument.', action='append'), dict(name="--raid-type", help="RAID type for the new RAID group. " "Should be one of these:\n %s" % "\n ". join(VolumeRAIDInfo.VOL_CREATE_RAID_TYPES_STR), choices=VolumeRAIDInfo.VOL_CREATE_RAID_TYPES_STR, type=_upper), ], optional=[ dict(name="--strip-size", help="Strip size. " + size_help), ], ), dict( name='volume-raid-create-cap', help='Query capability of creating a RAIDed volume on hardware RAID', args=[ dict(sys_id_opt), ], ), dict( name='volume-delete', help='Deletes a volume given its id', args=[ dict(vol_id_opt), ], ), dict( name='volume-resize', help='Re-sizes a volume', args=[ dict(vol_id_opt), dict(name='--size', metavar='', help="New size. %s" % size_help), ], ), dict( name='volume-replicate', help='Creates a new volume and replicates provided volume to it.', args=[ dict(vol_id_opt), dict(name="--name", metavar='', help='The name for New replicated volume'), dict(name="--rep-type", metavar='', help=replicate_help, choices=replicate_types), ], optional=[ dict(name="--pool", help='Pool ID to contain the new volume.\nBy default, ' 'new volume will be created in the same pool.'), ], ), dict( name='volume-replicate-range', help='Replicates a portion of a volume to existing volume', args=[ dict(name="--src-vol", metavar='', help='Source volume id'), dict(name="--dst-vol", metavar='', help='Destination volume id'), dict(name="--rep-type", metavar='', help="Replication type: CLONE, COPY", choices=["CLONE", "COPY"]), dict(name="--src-start", metavar='', help='Source volume start block number.\n' 'This is repeatable argument.', action='append', type=_check_positive_integer), dict(name="--dst-start", metavar='', help='Destination volume start block number.\n' 'This is repeatable argument.', action='append', type=_check_positive_integer), dict(name="--count", metavar='', help='Number of blocks to replicate.\n' 'This is repeatable argument.', action='append', type=_check_positive_integer), ], ), dict( name='volume-replicate-range-block-size', help='Size of each replicated block on a system in bytes', args=[ dict(sys_id_opt), ], ), dict( name='volume-dependants', help='Returns True if volume has a dependant child, like replication', args=[ dict(vol_id_opt), ], ), dict( name='volume-dependants-rm', help='Removes volume dependencies', args=[ dict(vol_id_opt), ], ), dict( name='volume-access-group', help='Lists the access group(s) that have access to volume', args=[ dict(vol_id_opt), ], ), dict( name='volume-mask', help='Grants access to an access group to a volume, ' 'like LUN Masking', args=[ dict(vol_id_opt), dict(ag_id_opt), ], ), dict( name='volume-unmask', help='Revoke the access of specified access group to a volume', args=[ dict(ag_id_opt), dict(vol_id_opt), ], ), dict( name='volume-enable', help='Enable block access of a volume', args=[ dict(vol_id_opt), ], ), dict( name='volume-disable', help='Disable block access of a volume', args=[ dict(vol_id_opt), ], ), dict( name='volume-raid-info', help='Query volume RAID information', args=[ dict(vol_id_opt), ], ), dict( name='volume-ident-led-on', help='Enable the IDENT LED for a volume', args=[ dict(name="--vol", metavar='', help='Targeted volume.\n'), ], ), dict( name='volume-ident-led-off', help='Disable the IDENT LED for a volume', args=[ dict(name="--vol", metavar='', help='Targeted volume.\n'), ], ), dict( name='system-read-cache-pct-update', help='Change the read cache percentage of a system', args=[ dict(name="--sys", metavar='', help='Targeted system.\n'), dict(name="--read-pct", help="Read cache percentage.\n", type=_check_positive_integer), ], ), dict( name='pool-member-info', help='Query Pool membership information', args=[ dict(pool_id_opt), ], ), dict( name='access-group-create', help='Create an access group', args=[ dict(name='--name', metavar='', help="Human readable name for access group"), # TODO: _client.py access_group_create should support multiple # initiators when creating. dict(init_id_opt), dict(sys_id_opt), ], ), dict( name='access-group-add', help='Add an initiator into existing access group', args=[ dict(ag_id_opt), dict(init_id_opt), ], ), dict( name='access-group-remove', help='Remove an initiator from existing access group', args=[ dict(ag_id_opt), dict(init_id_opt), ], ), dict( name='access-group-delete', help='Deletes an access group', args=[ dict(ag_id_opt), ], ), dict( name='access-group-volumes', help='Lists the volumes that the access group has' ' been granted access to', args=[ dict(ag_id_opt), ], ), dict( name='iscsi-chap', help='Configures iSCSI inbound/outbound CHAP authentication', args=[ dict(init_id_opt), ], optional=[ dict(name="--in-user", metavar='', help='Inbound chap user name'), dict(name="--in-pass", metavar='', help='Inbound chap password'), dict(name="--out-user", metavar='', help='Outbound chap user name'), dict(name="--out-pass", metavar='', help='Outbound chap password'), ], ), dict( name='fs-create', help='Creates a file system', args=[ dict(name="--name", metavar='', help='name of the file system'), dict(size_opt), dict(pool_id_opt), ], ), dict( name='fs-delete', help='Delete a filesystem', args=[ dict(fs_id_opt) ], ), dict( name='fs-resize', help='Re-sizes a filesystem', args=[ dict(fs_id_opt), dict(name="--size", metavar="", help="New size. %s" % size_help), ], ), dict( name='fs-export', help='Export a filesystem via NFS.', args=[ dict(fs_id_opt), ], optional=[ dict(name="--exportpath", metavar='', help="NFS server export path. e.g. '/foo/bar'."), dict(name="--anonuid", metavar='', help='UID(User ID) to map to anonymous user', default=NfsExport.ANON_UID_GID_NA, type=_check_positive_integer), dict(name="--anongid", metavar='', help='GID(Group ID) to map to anonymous user', default=NfsExport.ANON_UID_GID_NA, type=_check_positive_integer), dict(name="--auth-type", metavar='', help='NFS client authentication type'), dict(name="--root-host", metavar='', help="The host/IP has root access.\n" "This is repeatable argument.", action='append', default=[], type=_check_network_host), dict(name="--ro-host", metavar='', help="The host/IP has readonly access.\n" "This is repeatable argument.\n" "At least one '--ro-host' or '--rw-host' is required.", action='append', default=[], type=_check_network_host), dict(name="--rw-host", metavar='', help="The host/IP has readwrite access.\n" "This is repeatable argument.\n" "At least one '--ro-host' or '--rw-host' is required.", action='append', default=[], type=_check_network_host), ], ), dict( name='fs-unexport', help='Remove an NFS export', args=[ dict(export_id_opt), ], ), dict( name='fs-clone', help='Creates a file system clone', args=[ dict(name="--src-fs", metavar='', help='The ID of existing source file system.'), dict(name="--dst-name", metavar='', help='The name for newly created destination file system.'), ], optional=[ dict(name="--backing-snapshot", metavar='', help='backing snapshot id'), ], ), dict( name='fs-snap-create', help='Creates a snapshot', args=[ dict(name="--name", metavar="", help='The human friendly name of new snapshot'), dict(fs_id_opt), ], ), dict( name='fs-snap-delete', help='Deletes a snapshot', args=[ dict(snap_id_opt), dict(fs_id_opt), # TODO: why we need filesystem ID? ], ), dict( name='fs-snap-restore', help='Restores a FS or specified files to ' 'previous snapshot state', args=[ dict(snap_id_opt), dict(fs_id_opt), ], optional=[ dict(name="--file", metavar="", help="Only restore provided file\n" "Without this argument, all files will be restored\n" "This is a repeatable argument.", action='append', default=[]), dict(name="--fileas", metavar="", help="store restore file name to another name.\n" "This is a repeatable argument.", action='append', default=[]), ], ), dict( name='fs-dependants', help='Returns True if filesystem has a child ' 'dependency(clone/snapshot) exists', args=[ dict(fs_id_opt), ], optional=[ dict(name="--file", metavar="", action="append", default=[], help="For file check\nThis is a repeatable argument."), ], ), dict( name='fs-dependants-rm', help='Removes file system dependencies', args=[ dict(fs_id_opt), ], optional=[ dict(name="--file", action='append', default=[], help='File or files to remove dependencies for.\n' "This is a repeatable argument.",), ], ), dict( name='file-clone', help='Creates a clone of a file (thin provisioned)', args=[ dict(fs_id_opt), dict(name="--src", metavar="", help='source file to clone (relative path)\n' "This is a repeatable argument.",), dict(name="--dst", metavar="", help='Destination file (relative path)' ", this is a repeatable argument."), ], optional=[ dict(name="--backing-snapshot", help='backing snapshot id'), ], ), dict( name='local-disk-list', help='Query local disk information', args=[ ], optional=[ ], ), dict( name='volume-cache-info', help='Query volume RAM cache information', args=[ dict(vol_id_opt), ], ), dict( name='volume-phy-disk-cache-update', help='Update volume physical disk cache setting', args=[ dict(vol_id_opt), dict(policy_opt), ], ), dict( name='volume-read-cache-policy-update', help='Update volume read cache policy', args=[ dict(vol_id_opt), dict(policy_opt), ], ), dict( name='volume-write-cache-policy-update', help='Update volume write cache policy', args=[ dict(vol_id_opt), dict(write_cache_policy_opt), ], ), dict( name='local-disk-ident-led-on', help='Turn on the identification LED for a local disk', args=[ dict(local_disk_path_opt), ], ), dict( name='local-disk-ident-led-off', help='Turn off the identification LED for a local disk', args=[ dict(local_disk_path_opt), ], ), dict( name='local-disk-fault-led-on', help='Turn on the fault LED for a local disk', args=[ dict(local_disk_path_opt), ], ), dict( name='local-disk-fault-led-off', help='Turn off the fault LED for a local disk', args=[ dict(local_disk_path_opt), ], ), ) aliases = dict( ls='list --type systems', lp='list --type pools', lv='list --type volumes', ld='list --type disks', la='list --type access_groups', lf='list --type fs', lt='list --type target_ports', c='capabilities', p='plugin-info', vc='volume-create', vrc='volume-raid-create', vrcc='volume-raid-create-cap', vd='volume-delete', vr='volume-resize', vm='volume-mask', vu='volume-unmask', ve='volume-enable', vi='volume-disable', ac='access-group-create', aa='access-group-add', ar='access-group-remove', ad='access-group-delete', vri='volume-raid-info', vilon='volume-ident-led-on', viloff='volume-ident-led-off', srcpu='system-read-cache-pct-update', pmi='pool-member-info', ldl='local-disk-list', lb='list --type batteries', vci='volume-cache-info', vpdcu='volume-phy-disk-cache-update', vrcpu='volume-read-cache-policy-update', vwcpu='volume-write-cache-policy-update', ldilon='local-disk-ident-led-on', ldiloff='local-disk-ident-led-off', ldflon='local-disk-fault-led-on', ldfloff='local-disk-fault-led-off', ) # Class that encapsulates the command line arguments for lsmcli # Note: This class is used by lsmcli and any python plug-ins. class CmdLine(object): """ Command line interface class. """ ## # Warn of imminent data loss # @param deleting Indicate data will be lost vs. may be lost # (re-size) # @return True if operation confirmed, else False def confirm_prompt(self, deleting): """ Give the user a chance to bail. """ if not self.args.force: msg = "will" if deleting else "may" out("Warning: You are about to do an operation that %s cause data " "to be lost!\nPress [Y|y] to continue, any other key to abort" % msg) pressed = getch() if pressed.upper() == 'Y': return True else: out('Operation aborted!') return False else: return True ## # Tries to make the output better when it varies considerably from # plug-in to plug-in. # @param objects Data, first row is header all other data. def display_data(self, objects): display_all = False if len(objects) == 0: return display_way = DisplayData.DISPLAY_WAY_DEFAULT flag_with_header = True if self.args.sep: flag_with_header = False if self.args.header: flag_with_header = True if self.args.script: display_way = DisplayData.DISPLAY_WAY_SCRIPT DisplayData.display_data( objects, display_way=display_way, flag_human=self.args.human, flag_enum=self.args.enum, splitter=self.args.sep, flag_with_header=flag_with_header, flag_dsp_all_data=display_all) def display_available_plugins(self): d = [] sep = '<}{>' plugins = Client.available_plugins(sep) for p in plugins: desc, version = p.split(sep) d.append(PlugData(desc, version)) self.display_data(d) @staticmethod def handle_alias(): """ Walk the command line argument list and build up a new command line with the appropriate substitutions which is then passed to argparse, so that we can avoid adding more sub parsers and do all argument parsing before the need to talk to the library :return copy of command line args with alias expansion: """ rc = [] for i in sys.argv[1:]: if i in aliases: rc.extend(aliases[i].split(" ")) else: rc.append(i) return rc @staticmethod def alias_help_text(): rc = "command aliases:\n" for k, v in sorted(aliases.items()): rc += " {0:<18} Alias of '{1}'\n".format(k, v) return rc # All the command line arguments and options are created in this method def cli(self): """ Command line interface parameters """ parent_parser = ArgumentParser(add_help=False) _add_common_options(parent_parser, is_child=True) parser = ArgumentParser( description='The libStorageMgmt command line interface.' ' Run %(prog)s -h for more on each command.', epilog=CmdLine.alias_help_text() + '\n\nCopyright 2012-2018 Red Hat, Inc.\n' 'Please report bugs to ' '\n', formatter_class=RawTextHelpFormatter) _add_common_options(parser, is_child=False) subparsers = parser.add_subparsers(metavar="command") # Walk the command list and add all of them to the parser for cmd in cmds: sub_parser = subparsers.add_parser( cmd['name'], help=cmd['help'], parents=[parent_parser], formatter_class=RawTextHelpFormatter) group = sub_parser.add_argument_group("cmd required arguments") for arg in cmd.get('args', []): name = arg['name'] del arg['name'] group.add_argument(name, required=True, **arg) group = sub_parser.add_argument_group("cmd optional arguments") for arg in cmd.get('optional', []): flags = arg['name'] del arg['name'] if not isinstance(flags, tuple): flags = (flags,) group.add_argument(*flags, **arg) sub_parser.set_defaults( func=getattr(self, cmd['name'].replace("-", "_"))) if len(sys.argv) == 1: parser.print_usage() exit(1) self.parser = parser known_args = parser.parse_args(args=CmdLine.handle_alias()) # Copy child value to root. for k, v in vars(known_args).items(): if k.startswith(_CHILD_OPTION_DST_PREFIX): root_k = k[len(_CHILD_OPTION_DST_PREFIX):] if getattr(known_args, root_k) is None or \ getattr(known_args, root_k) is False: setattr(known_args, root_k, v) return known_args # Display the types of nfs client authentication that are supported. # @return None def display_nfs_client_authentication(self): """ Dump the supported nfs client authentication types """ if self.args.sep: out(self.args.sep.join(self.c.export_auth())) else: out(", ".join(self.c.export_auth())) # Determine what the search key and search value are for listing # @param args Argparse argument object # @return (key, value) tuple @staticmethod def _get_search_key_value(args): search_key = None search_value = None search_args = ((args.sys, 'system_id'), (args.pool, 'pool_id'), (args.vol, 'volume_id'), (args.disk, 'disk_id'), (args.ag, 'access_group_id'), (args.fs, 'fs_id'), (args.nfs_export, 'nfs_export_id'), (args.tgt, 'tgt_port_id')) for sa in search_args: if sa[0]: if search_key: raise ArgError( "Search key specified more than once (%s, %s)" % (search_key, sa[1])) else: (search_value, search_key) = sa return search_key, search_value # Method that calls the appropriate method based on what the list type is # @param args Argparse argument object def list(self, args): (search_key, search_value) = CmdLine._get_search_key_value(args) if args.type == 'VOLUMES': lsm_vols = [] if search_key == 'volume_id': search_key = 'id' if search_key == 'access_group_id': lsm_ag = _get_item(self.c.access_groups(), args.ag, "Access Group", raise_error=False) if lsm_ag: lsm_vols = self.c.volumes_accessible_by_access_group( lsm_ag) elif search_key and search_key not in Volume.SUPPORTED_SEARCH_KEYS: raise ArgError("Search key '%s' is not supported by " "volume listing." % search_key) else: lsm_vols = self.c.volumes(search_key, search_value) self.display_data(list(_add_sd_paths(v) for v in lsm_vols)) elif args.type == 'POOLS': if search_key == 'pool_id': search_key = 'id' if search_key and search_key not in Pool.SUPPORTED_SEARCH_KEYS: raise ArgError("Search key '%s' is not supported by " "pool listing." % search_key) self.display_data( self.c.pools(search_key, search_value)) elif args.type == 'FS': if search_key == 'fs_id': search_key = 'id' if search_key and \ search_key not in FileSystem.SUPPORTED_SEARCH_KEYS: raise ArgError("Search key '%s' is not supported by " "volume listing." % search_key) self.display_data(self.c.fs(search_key, search_value)) elif args.type == 'SNAPSHOTS': if args.fs is None: raise ArgError("--fs required") if search_key and search_key != "fs_id": raise ArgError("Search key '%s' is not supported by " "snapshot listing." % search_key) fs = _get_item(self.c.fs(), args.fs, 'File System') self.display_data(self.c.fs_snapshots(fs)) elif args.type == 'EXPORTS': if search_key == 'nfs_export_id': search_key = 'id' if search_key and \ search_key not in NfsExport.SUPPORTED_SEARCH_KEYS: raise ArgError("Search key '%s' is not supported by " "NFS Export listing" % search_key) self.display_data(self.c.exports(search_key, search_value)) elif args.type == 'NFS_CLIENT_AUTH': if search_key: raise ArgError("NFS client authentication type listing with " "search is not supported") self.display_nfs_client_authentication() elif args.type == 'ACCESS_GROUPS': if search_key == 'access_group_id': search_key = 'id' if search_key == 'volume_id': lsm_vol = _get_item(self.c.volumes(), args.vol, "Volume", raise_error=False) if lsm_vol: return self.display_data( self.c.access_groups_granted_to_volume(lsm_vol)) else: return self.display_data([]) elif (search_key and search_key not in AccessGroup.SUPPORTED_SEARCH_KEYS): raise ArgError("Search key '%s' is not supported by " "Access Group listing" % search_key) self.display_data( self.c.access_groups(search_key, search_value)) elif args.type == 'SYSTEMS': if search_key: raise ArgError("System listing with search is not supported") self.display_data(self.c.systems()) elif args.type == 'DISKS': if search_key == 'disk_id': search_key = 'id' if search_key and search_key not in Disk.SUPPORTED_SEARCH_KEYS: raise ArgError("Search key '%s' is not supported by " "disk listing" % search_key) self.display_data( list(_add_sd_paths(d) for d in self.c.disks(search_key, search_value))) elif args.type == 'TARGET_PORTS': if search_key == 'tgt_port_id': search_key = 'id' if search_key and \ search_key not in TargetPort.SUPPORTED_SEARCH_KEYS: raise ArgError("Search key '%s' is not supported by " "target port listing" % search_key) self.display_data( self.c.target_ports(search_key, search_value)) elif args.type == 'PLUGINS': if search_key: raise ArgError("Plugins listing with search is not supported") self.display_available_plugins() elif args.type == 'BATTERIES': if search_key and \ search_key not in Battery.SUPPORTED_SEARCH_KEYS: raise ArgError("Search key '%s' is not supported by " "battery listing" % search_key) self.display_data( self.c.batteries(search_key, search_value)) else: raise ArgError("unsupported listing type=%s" % args.type) # Creates an access group. def access_group_create(self, args): system = _get_item(self.c.systems(), args.sys, "System") (init_id, init_type) = parse_convert_init(args.init) access_group = self.c.access_group_create(args.name, init_id, init_type, system) self.display_data([access_group]) def _add_rm_access_grp_init(self, args, op): lsm_ag = _get_item(self.c.access_groups(), args.ag, "Access Group") (init_id, init_type) = parse_convert_init(args.init) if op: return self.c.access_group_initiator_add(lsm_ag, init_id, init_type) else: return self.c.access_group_initiator_delete(lsm_ag, init_id, init_type) # Adds an initiator from an access group def access_group_add(self, args): self.display_data([self._add_rm_access_grp_init(args, True)]) # Removes an initiator from an access group def access_group_remove(self, args): self.display_data([self._add_rm_access_grp_init(args, False)]) def access_group_volumes(self, args): agl = self.c.access_groups() group = _get_item(agl, args.ag, "Access Group") vols = self.c.volumes_accessible_by_access_group(group) self.display_data(list(_add_sd_paths(v) for v in vols)) def iscsi_chap(self, args): (init_id, init_type) = parse_convert_init(args.init) if init_type != AccessGroup.INIT_TYPE_ISCSI_IQN: raise ArgError("--init \"%s\" is not a valid iSCSI IQN" % args.init) if self.args.in_user and not self.args.in_pass: raise ArgError("--in-user requires --in-pass") if self.args.in_pass and not self.args.in_user: raise ArgError("--in-pass requires --in-user") if self.args.out_user and not self.args.out_pass: raise ArgError("--out-user requires --out-pass") if self.args.out_pass and not self.args.out_user: raise ArgError("--out-pass requires --out-user") # Enforce consistency across all if self.args.out_user and self.args.out_pass and not \ (self.args.in_user and self.args.in_pass): raise ArgError("out-user and out-password only supported if " "inbound is supplied") self.c.iscsi_chap_auth(init_id, args.in_user, self.args.in_pass, self.args.out_user, self.args.out_pass) def volume_access_group(self, args): vol = _get_item(self.c.volumes(), args.vol, "Volume") groups = self.c.access_groups_granted_to_volume(vol) self.display_data(groups) # Used to delete access group def access_group_delete(self, args): agl = self.c.access_groups() group = _get_item(agl, args.ag, "Access Group") return self.c.access_group_delete(group) # Used to delete a file system def fs_delete(self, args): fs = _get_item(self.c.fs(), args.fs, "File System") if self.confirm_prompt(True): self._wait_for_it("fs-delete", self.c.fs_delete(fs), None) # Used to create a file system def fs_create(self, args): p = _get_item(self.c.pools(), args.pool, "Pool") fs = self._wait_for_it("fs-create", *self.c.fs_create(p, args.name, self._size(args.size))) self.display_data([fs]) # Used to resize a file system def fs_resize(self, args): fs = _get_item(self.c.fs(), args.fs, "File System") size = self._size(args.size) if size == fs.total_space: raise LsmError( ErrorNumber.NO_STATE_CHANGE, "Specified size same as current") if self.confirm_prompt(False): fs = self._wait_for_it("fs-resize", *self.c.fs_resize(fs, size)) self.display_data([fs]) # Used to clone a file system def fs_clone(self, args): src_fs = _get_item( self.c.fs(), args.src_fs, "Source File System") ss = None if args.backing_snapshot: # go get the snapshot ss = _get_item(self.c.fs_snapshots(src_fs), args.backing_snapshot, "Snapshot") fs = self._wait_for_it( "fs_clone", *self.c.fs_clone(src_fs, args.dst_name, ss)) self.display_data([fs]) # Used to clone a file(s) def file_clone(self, args): fs = _get_item(self.c.fs(), args.fs, "File System") if self.args.backing_snapshot: # go get the snapshot ss = _get_item(self.c.fs_snapshots(fs), args.backing_snapshot, "Snapshot") else: ss = None self._wait_for_it( "fs_file_clone", self.c.fs_file_clone(fs, args.src, args.dst, ss), None) # Converts a size parameter into the appropriate number of bytes # @param s Size to convert to bytes handles B, K, M, G, T, P postfix # @return Size in bytes @staticmethod def _size(s): size_bytes = size_human_2_size_bytes(s) if size_bytes <= 0: raise ArgError("Incorrect size argument format: '%s'" % s) return size_bytes def _cp(self, cap, val): if self.args.sep is not None: s = self.args.sep else: s = ':' if val: v = "SUPPORTED" else: v = "UNSUPPORTED" out("%s%s%s" % (cap, s, v)) def capabilities(self, args): s = _get_item(self.c.systems(), args.sys, "System") cap = self.c.capabilities(s) sup_caps = sorted(cap.get_supported().values()) all_caps = sorted(cap.get_supported(True).values()) sep = DisplayData.DEFAULT_SPLITTER if self.args.sep is not None: sep = self.args.sep cap_data = OrderedDict() # Show support capabilities first for v in sup_caps: cap_data[v] = 'SUPPORTED' for v in all_caps: if v not in sup_caps: cap_data[v] = 'UNSUPPORTED' DisplayData.display_data_script_way([cap_data], sep) def plugin_info(self, args): desc, version = self.c.plugin_info() if args.sep: out("%s%s%s" % (desc, args.sep, version)) else: out("Description: %s Version: %s" % (desc, version)) # Creates a volume def volume_create(self, args): # Get pool p = _get_item(self.c.pools(), args.pool, "Pool") vol = self._wait_for_it( "volume-create", *self.c.volume_create( p, args.name, self._size(args.size), vol_provision_str_to_type(args.provisioning))) self.display_data([_add_sd_paths(vol)]) # Creates a snapshot def fs_snap_create(self, args): # Get fs fs = _get_item(self.c.fs(), args.fs, "File System") ss = self._wait_for_it("snapshot-create", *self.c.fs_snapshot_create( fs, args.name)) self.display_data([ss]) # Restores a snap shot def fs_snap_restore(self, args): # Get snapshot fs = _get_item(self.c.fs(), args.fs, "File System") ss = _get_item(self.c.fs_snapshots(fs), args.snap, "Snapshot") files = self.args.file if len(files) == 0: files = None flag_all_files = True if self.args.file: flag_all_files = False if self.args.fileas: if len(self.args.file) != len(self.args.fileas): raise ArgError( "number of --file not equal to --fileas") if self.confirm_prompt(True): self._wait_for_it( 'fs-snap-restore', self.c.fs_snapshot_restore( fs, ss, files, self.args.fileas, flag_all_files), None) # Deletes a volume def volume_delete(self, args): v = _get_item(self.c.volumes(), args.vol, "Volume") if self.confirm_prompt(True): self._wait_for_it("volume-delete", self.c.volume_delete(v), None) # Deletes a snap shot def fs_snap_delete(self, args): fs = _get_item(self.c.fs(), args.fs, "File System") ss = _get_item(self.c.fs_snapshots(fs), args.snap, "Snapshot") if self.confirm_prompt(True): self._wait_for_it("fs_snap_delete", self.c.fs_snapshot_delete(fs, ss), None) # Waits for an operation to complete by polling for the status of the # operations. # @param msg Message to display if this job fails # @param job The job id to wait on # @param item The item that could be available now if there is no job def _wait_for_it(self, msg, job, item): if not job: return item else: # If a user doesn't want to wait, return the job id to stdout # and exit with job in progress if self.args._async: out(job) self.shutdown(ErrorNumber.JOB_STARTED) while True: (s, percent, item) = self.c.job_status(job) if s == JobStatus.INPROGRESS: # Add an option to spit out progress? # print "%s - Percent %s complete" % (job, percent) time.sleep(0.25) elif s == JobStatus.COMPLETE: self.c.job_free(job) return item else: # Something better to do here? raise ArgError(msg + " job error code= " + str(s)) # Retrieves the status of the specified job def job_status(self, args): (s, percent, item) = self.c.job_status(args.job) if s == JobStatus.COMPLETE: if item: self.display_data([_add_sd_paths(item)]) self.c.job_free(args.job) else: out(str(percent)) self.shutdown(ErrorNumber.JOB_STARTED) # Replicates a volume def volume_replicate(self, args): p = None if args.pool: p = _get_item(self.c.pools(), args.pool, "Pool") v = _get_item(self.c.volumes(), args.vol, "Volume") rep_type = vol_rep_type_str_to_type(args.rep_type) if rep_type == Volume.REPLICATE_UNKNOWN: raise ArgError("invalid replication type= %s" % rep_type) vol = self._wait_for_it( "replicate volume", *self.c.volume_replicate(p, rep_type, v, args.name)) self.display_data([_add_sd_paths(vol)]) # Check to see if block ranges are overlapping @staticmethod def _check_overlap(ranges): def _overlap(r, member): for i in range(1, len(r)): ps = getattr(r[i - 1], member) # Previous start pc = r[i - 1].block_count # Previous count cs = getattr(r[i], member) # Current start cc = r[i].block_count # Current count if ps + pc > cs: raise ArgError("Overlapping %s replication " "range %d..%d overlaps with %d..%d" % (member, ps, ps + pc - 1, cs, cs + cc - 1)) # Sort the src ranges ranges.sort(key=lambda x: x.src_block) _overlap(ranges, "src_block") ranges.sort(key=lambda x: x.dest_block) _overlap(ranges, "dest_block") # Replicates a range of a volume def volume_replicate_range(self, args): src = _get_item(self.c.volumes(), args.src_vol, "Source Volume") dst = _get_item(self.c.volumes(), args.dst_vol, "Destination Volume") rep_type = vol_rep_type_str_to_type(args.rep_type) if rep_type == Volume.REPLICATE_UNKNOWN: raise ArgError("invalid replication type= %s" % rep_type) src_starts = args.src_start dst_starts = args.dst_start counts = args.count if not len(src_starts) \ or not (len(src_starts) == len(dst_starts) == len(counts)): raise ArgError("Differing numbers of src_start, dest_start, " "and count parameters") ranges = [] for b in range(len(src_starts)): # Validate some assumptions for source & count count = long(counts[b]) src_start = long(src_starts[b]) dst_start = long(dst_starts[b]) if count < 0: raise ArgError("--count: value < 0") if src_start < 0: raise ArgError("--src-start: value < 0") if dst_start < 0: raise ArgError("--dst_start: value < 0") if src_start + count > src.num_of_blocks: raise ArgError("--src-start + --count > source size") if dst_start + count > dst.num_of_blocks: raise ArgError("--dst-start + --count > destination size") ranges.append(BlockRange(src_start, dst_start, count)) CmdLine._check_overlap(ranges) if self.confirm_prompt(False): self.c.volume_replicate_range(rep_type, src, dst, ranges) # # Returns the block size in bytes for each block represented in # volume_replicate_range def volume_replicate_range_block_size(self, args): s = _get_item(self.c.systems(), args.sys, "System") out(self.c.volume_replicate_range_block_size(s)) def volume_mask(self, args): vol = _get_item(self.c.volumes(), args.vol, 'Volume') ag = _get_item(self.c.access_groups(), args.ag, 'Access Group') self.c.volume_mask(ag, vol) def volume_unmask(self, args): ag = _get_item(self.c.access_groups(), args.ag, "Access Group") vol = _get_item(self.c.volumes(), args.vol, "Volume") return self.c.volume_unmask(ag, vol) # Re-sizes a volume def volume_resize(self, args): v = _get_item(self.c.volumes(), args.vol, "Volume") size = self._size(args.size) if size == v.block_size * v.num_of_blocks: raise LsmError( ErrorNumber.NO_STATE_CHANGE, "Specified size same as current") if self.confirm_prompt(False): vol = self._wait_for_it("resize", *self.c.volume_resize(v, size)) self.display_data([_add_sd_paths(vol)]) # Enable a volume def volume_enable(self, args): v = _get_item(self.c.volumes(), args.vol, "Volume") self.c.volume_enable(v) # Disable a volume def volume_disable(self, args): v = _get_item(self.c.volumes(), args.vol, "Volume") self.c.volume_disable(v) # Removes a nfs export def fs_unexport(self, args): export = _get_item(self.c.exports(), args.export, "NFS Export") self.c.export_remove(export) # Exports a file system as a NFS export def fs_export(self, args): fs = _get_item(self.c.fs(), args.fs, "File System") # Check to see if we have some type of access specified if len(args.rw_host) == 0 \ and len(args.ro_host) == 0: raise ArgError(" please specify --ro-host or --rw-host") export = self.c.export_fs( fs.id, args.exportpath, args.root_host, args.rw_host, args.ro_host, args.anonuid, args.anongid, args.auth_type, None) self.display_data([export]) # Displays volume dependants. def volume_dependants(self, args): v = _get_item(self.c.volumes(), args.vol, "Volume") rc = self.c.volume_child_dependency(v) out(rc) # Removes volume dependants. def volume_dependants_rm(self, args): v = _get_item(self.c.volumes(), args.vol, "Volume") self._wait_for_it("volume-dependant-rm", self.c.volume_child_dependency_rm(v), None) def volume_raid_info(self, args): lsm_vol = _get_item(self.c.volumes(), args.vol, "Volume") self.display_data( [ VolumeRAIDInfo( lsm_vol.id, *self.c.volume_raid_info(lsm_vol))]) def pool_member_info(self, args): lsm_pool = _get_item(self.c.pools(), args.pool, "Pool") self.display_data( [ PoolRAIDInfo( lsm_pool.id, *self.c.pool_member_info(lsm_pool))]) def volume_raid_create(self, args): raid_type = VolumeRAIDInfo.raid_type_str_to_lsm(args.raid_type) all_lsm_disks = self.c.disks() lsm_disks = [d for d in all_lsm_disks if d.id in args.disk] if len(lsm_disks) != len(args.disk): raise LsmError( ErrorNumber.NOT_FOUND_DISK, "Disk ID %s not found" % ', '.join(set(args.disk) - set(d.id for d in all_lsm_disks))) busy_disks = [d.id for d in lsm_disks if not d.status & Disk.STATUS_FREE] if len(busy_disks) >= 1: raise LsmError( ErrorNumber.DISK_NOT_FREE, "Disk %s is not free" % ", ".join(busy_disks)) if args.strip_size: strip_size = size_human_2_size_bytes(args.strip_size) else: strip_size = Volume.VCR_STRIP_SIZE_DEFAULT self.display_data([ _add_sd_paths( self.c.volume_raid_create( args.name, raid_type, lsm_disks, strip_size))]) def volume_raid_create_cap(self, args): lsm_sys = _get_item(self.c.systems(), args.sys, "System") self.display_data([ VcrCap(lsm_sys.id, *self.c.volume_raid_create_cap_get(lsm_sys))]) def volume_ident_led_on(self, args): lsm_volume = _get_item(self.c.volumes(), args.vol, "Volume") self.c.volume_ident_led_on(lsm_volume) def volume_ident_led_off(self, args): lsm_volume = _get_item(self.c.volumes(), args.vol, "Volume") self.c.volume_ident_led_off(lsm_volume) def system_read_cache_pct_update(self, args): lsm_system = _get_item(self.c.systems(), args.sys, "System") try: read_pct = int(args.read_pct) except ValueError as ve: raise LsmError(ErrorNumber.INVALID_ARGUMENT, str(ve)) self.c.system_read_cache_pct_update(lsm_system, read_pct) lsm_system = _get_item(self.c.systems(), args.sys, "System") self.display_data([lsm_system]) # Displays file system dependants def fs_dependants(self, args): fs = _get_item(self.c.fs(), args.fs, "File System") rc = self.c.fs_child_dependency(fs, args.file) out(rc) # Removes file system dependants def fs_dependants_rm(self, args): fs = _get_item(self.c.fs(), args.fs, "File System") self._wait_for_it("fs-dependants-rm", self.c.fs_child_dependency_rm(fs, args.file), None) def _read_configfile(self): """ Set uri from config file. Will be overridden by cmdline option or env var if present. """ allowed_config_options = ("uri",) config_path = os.path.expanduser("~") + "/.lsmcli" if not os.path.exists(config_path): return with open(config_path) as f: for line in f: if line.lstrip().startswith("#"): continue try: name, val = [x.strip() for x in line.split("=", 1)] if name in allowed_config_options: setattr(self, name, val) except ValueError: pass def is_connection_free_cmd(self): """ Return True if current command is one of _CONNECTION_FREE_COMMANDS. """ if self.args.func.__name__.replace("_", "-") in \ _CONNECTION_FREE_COMMANDS: return True return False # Class constructor. def __init__(self): self.uri = None self.c = None self.parser = None self.unknown_args = None self.args = self.cli() self.cleanup = None self.tmo = int(self.args.wait) if not self.tmo or self.tmo < 0: raise ArgError("[-w|--wait] requires a non-zero positive integer") if self.is_connection_free_cmd(): return self._read_configfile() if os.getenv('LSMCLI_URI') is not None: self.uri = os.getenv('LSMCLI_URI') self.password = os.getenv('LSMCLI_PASSWORD') if self.args.uri is not None: self.uri = self.args.uri if self.uri is None: # We need a valid plug-in to instantiate even if all we are trying # to do is list the plug-ins at the moment to keep that code # the same in all cases, even though it isn't technically # required for the client library (static method) # TODO: Make this not necessary. if 'type' in self.args and self.args.type == "PLUGINS": self.uri = "sim://" self.password = None else: raise ArgError("--uri missing or export LSMCLI_URI") # Lastly get the password if requested. if self.args.prompt: self.password = getpass.getpass() if self.password is not None: # Check for username u = uri_parse(self.uri) if u['username'] is None: raise ArgError("password specified with no user name in uri") # Does appropriate clean-up # @param ec The exit code def shutdown(self, ec=None): if self.cleanup: self.cleanup() if ec: sys.exit(ec) # Process the specified command # @param cli The object instance to invoke methods on. def process(self, cli=None): """ Process the parsed command. """ if self.is_connection_free_cmd(): self.args.func(self.args) else: if cli: # Directly invoking code though a wrapper to catch unsupported # operations. self.c = Proxy(cli()) self.c.plugin_register(self.uri, self.password, self.tmo) self.cleanup = self.c.plugin_unregister else: # Going across the ipc pipe self.c = Proxy(Client(self.uri, self.password, self.tmo)) if os.getenv('LSM_DEBUG_PLUGIN'): input("Attach debugger to plug-in, " "press when ready...") self.cleanup = self.c.close self.args.func(self.args) self.shutdown() def local_disk_list(self, args): local_disks = [] func_dict = { "vpd83": LocalDisk.vpd83_get, "rpm": LocalDisk.rpm_get, "link_type": LocalDisk.link_type_get, "serial_num": LocalDisk.serial_num_get, "led_status": LocalDisk.led_status_get, "link_speed": LocalDisk.link_speed_get, "health_status": LocalDisk.health_status_get, } for disk_path in LocalDisk.list(): info_dict = { "vpd83": "", "rpm": Disk.RPM_NO_SUPPORT, "link_type": Disk.LINK_TYPE_NO_SUPPORT, "serial_num": "", "led_status": Disk.LED_STATUS_UNKNOWN, "link_speed": Disk.LINK_SPEED_UNKNOWN, "health_status": Disk.HEALTH_STATUS_UNKNOWN, } for key in info_dict.keys(): try: info_dict[key] = func_dict[key](disk_path) except LsmError as lsm_err: if lsm_err.code != ErrorNumber.NO_SUPPORT: sys.stderr.write("WARN: %s('%s'): %d %s\n" % (func_dict[key].__name__, disk_path, lsm_err.code, lsm_err.msg)) local_disks.append( LocalDiskInfo(disk_path, info_dict["vpd83"], info_dict["rpm"], info_dict["link_type"], info_dict["serial_num"], info_dict["led_status"], info_dict["link_speed"], info_dict["health_status"])) self.display_data(local_disks) def volume_cache_info(self, args): lsm_vol = _get_item(self.c.volumes(), args.vol, "Volume") self.display_data( [ VolumeRAMCacheInfo( lsm_vol.id, *self.c.volume_cache_info(lsm_vol))]) def volume_phy_disk_cache_update(self, args): lsm_vol = _get_item(self.c.volumes(), args.vol, "Volume") if args.policy == "ENABLE": policy = Volume.READ_CACHE_POLICY_ENABLED else: policy = Volume.READ_CACHE_POLICY_DISABLED self.c.volume_physical_disk_cache_update(lsm_vol, policy) self.display_data( [ VolumeRAMCacheInfo( lsm_vol.id, *self.c.volume_cache_info(lsm_vol))]) def volume_read_cache_policy_update(self, args): lsm_vol = _get_item(self.c.volumes(), args.vol, "Volume") if args.policy == "ENABLE": policy = Volume.PHYSICAL_DISK_CACHE_ENABLED else: policy = Volume.PHYSICAL_DISK_CACHE_DISABLED self.c.volume_read_cache_policy_update(lsm_vol, policy) self.display_data( [ VolumeRAMCacheInfo( lsm_vol.id, *self.c.volume_cache_info(lsm_vol))]) def volume_write_cache_policy_update(self, args): lsm_vol = _get_item(self.c.volumes(), args.vol, "Volume") if args.policy == 'WB': policy = Volume.WRITE_CACHE_POLICY_WRITE_BACK elif args.policy == 'AUTO': policy = Volume.WRITE_CACHE_POLICY_AUTO else: policy = Volume.WRITE_CACHE_POLICY_WRITE_THROUGH self.c.volume_write_cache_policy_update(lsm_vol, policy) self.display_data( [ VolumeRAMCacheInfo( lsm_vol.id, *self.c.volume_cache_info(lsm_vol))]) def local_disk_ident_led_on(self, args): LocalDisk.ident_led_on(args.path) def local_disk_ident_led_off(self, args): LocalDisk.ident_led_off(args.path) def local_disk_fault_led_on(self, args): LocalDisk.fault_led_on(args.path) def local_disk_fault_led_off(self, args): LocalDisk.fault_led_off(args.path) lsmcli/__init__.pyo000064400000000421147576505410010332 0ustar00 /P`c@s<yddlmZWn!ek r7ddlmZnXdS(i(tcmd_line_wrapperiN(tcmdlineRt ImportError(((s7/usr/lib/python2.7/site-packages/lsm/lsmcli/__init__.pyts lsmcli/cmdline.pyc000064400000170163147576505410010205 0ustar00 /P`cK@sddlZddlZddlZddlZddlZddlZddlZddlmZm Z ddlm Z ddl Z ddl m Z mZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZddlm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)dddd d gZ*e j+rie,Z-nydd l.m/Z/Wn!e0k rdd l1m/Z/nXdd Z3d Z4dZ5dZ6dZ7dZ8dZ9dZ:dZ;dZ<e=dZ>dZ?de@fdYZAdeBdZCdZDdddd d!d"d#d$d%d&d'd(g ZEdpZFd,d-jGeFZHdqZId2d-jGeIZJd3d4gZKd5d-jGeKZLeMd6d7d8d9d:eLd;eKd<e9ZNd=d>d?gZOd@d-jGeOdAdBZPeMd6d7d8d9d:ePd;eOd<e9ZQdCZReMd6dDd8dEd:dFZSeSjTZUdGeUd:dqeMeegeMd6d d:d?dqeMeegeMd6d d:d@dqeMeegf3ZheMdAdBdCdDdEdFdGdHdIdJdKdLdMdNdOd}dPddQddRddSddTddUddVddWddXddYddZdd[dd\dd]dd^dd_dd`ddaddbddcddddedfd5dgd7dhd9did;djddkddld dmd %ZidnejfdoYZkdS(riN(tArgumentParsertArgumentTypeError(tRawTextHelpFormatter(tClienttPooltVERSIONtLsmErrortDisktVolumet JobStatust ErrorNumbert BlockRanget uri_parsetProxytsize_human_2_size_bytest AccessGroupt FileSystemt NfsExportt TargetPortt LocalDisktBattery( t DisplayDatatPlugDatatouttvol_provision_str_to_typetvol_rep_type_str_to_typetVolumeRAIDInfot PoolRAIDInfotVcrCapt LocalDiskInfotVolumeRAMCacheInfoslocal-disk-listslocal-disk-ident-led-onslocal-disk-ident-led-offslocal-disk-fault-led-onslocal-disk-fault-led-off(t OrderedDictcCsbd}d}zyt}|j|Wntk rg}tjjt|tjjd}nt k r}tjjt|dtjj|j t j krd}qd}n]t k rd}nGtk r}|j }n,ddl}|jd tjd}nXWd|rPy|j|WqPtk rLqPXntj|XdS( s+ Common command line code, called. iis i iiiNtfile(tNonetCmdLinetprocesstArgErrortsyststderrtwritetstrtflushRtcodeR tPERMISSION_DENIEDtKeyboardInterruptt SystemExitt tracebackt print_exctstdouttshutdownt Exceptiontexit(tcterr_exittclitaetletseR.((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytcmd_line_wrapper;s<           cCshtjj}tj|}z,tjtjjtjjd}Wdtj|tj |X|S(Ni( R%tstdintfilenottermiost tcgetattrtttytsetrawtreadt tcsetattrt TCSADRAIN(tfdtprevtch((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytgetchhscCs<tj|\}}}|r(||fStd|dS(s If init_id is a WWPN, convert it into LSM standard version: (?:[0-9a-f]{2}:){7}[0-9a-f]{2} Return (converted_init_id, lsm_init_type) s,--init "%s" is not a valid WWPN or iSCSI IQNN(Rtinitiator_id_verifyR$(tinit_idtvalidtconverted_init_typetconverted_init_id((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytparse_convert_initss cCs6tj|\}}}|r"|Std|dS(s Call back from validating an initiator :param init_id: Initiator to validate :return: Value of initiator or raises an exception s!"%s" is invalid WWPN or iSCSI IQNN(RRHR(RIRJt_RL((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt _check_initscCs^y6t|d}|dkr1td|n|SWn!tk rYtd|nXdS(s Call back for validating a positive integer :param num: Number string to check :return: Numeric value, else exception i is,invalid: require positive integer value '%d's*invalid: not a positive integer value '%s'N(tlongRt ValueError(tnumtrc((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_check_positive_integers  tchild_cCs |jS(N(tupper(ts((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_upperscCs|s tS|jd}t|dkr/tSd|kr?tSx|D]}dt|koidknsrtSt|dkr|ddkrtSyt|dd krtSWqFtk rtSXqFWtS( s Check if a string represents a valid ip4 address :param address: String representing address :return: True if valid address, else false t.it/iiit0i i(tFalsetsplittlentintRQtTrue(taddresstpartsti((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_valid_ip4_addresss$  ""  cskdt}|stSd|kr&tSt|jddkrEtS|jd}t|dksxt|dkr|tSd|d krt|jsd GHtS|jd d gnd|krg|D]}|d kr|^q}|jd t}n|rt|d ks.t|d krgtd|Doftfdd j |DStS(s Check if a string represents a valid ipv6 address :param address: String representing address :return: True if valid address, else false sABCDEFabcdef0123456789:RZs::it:ii RYisNot valid ipv suffixR[ticss!|]}t|dkVqdS(iN(R^(t.0tx((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys sc3s|]}|kVqdS(N((RgRh(tallowed(s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys s( R\R^R]RdtpoptextendtappendR`talltjoin(Rat has_zerosRbtp((Ris6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_valid_ip6_addresss0 $ %  *#cstjdtjtjd}t|r4tSt|rDtSt|dkrZtS|j|rmtS|ddkr|d }nt fd|j dDS(s Checks to see if the supplied string is a valid ip4/6 or hostname :param ip_hn: String representing address user inputted :return: True if valid IP address or hostname s(?!-)[A-Z0-9-]{1,63}(?s( tretcompilet IGNORECASERdR`RqR^R\RrRmR](tip_hnt digits_only((Ris6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_is_valid_network_names   c Csd}|rt}n|jddddddtjdtf|jdd dd d td d dd|dd|jdddddd|dd|jdddddd|dd|jdddd dd|d ddd|jd d!dddd"|d#tdd$|jd%d&dddd'|d#tdd(|jd)d*dd dd+|dd,d t|jd-dddd.|dd/|jd0dddd1|d#tdd2|jd3d4dddd5|d#tdd6|rt}d7|d+|<|j |nd8S(9s As https://bugs.python.org/issue23058 indicate, argument parser should not have subparser sharing the same argument and destination. For subparser, we add common options as 'child_xxx' destination. For default value, False is the only allowed default value in root. Rfs-vs --versiontactiontversions%s %sis-us--uritstorettypetmetavarstdests%surithelps,Uniform resource identifier (env LSMCLI_URI)s-Ps--promptt store_trues%sprompts)Prompt for password (env LSMCLI_PASSWORD)s-Hs--humans%shumans:Print sizes in human readable format (e.g., MiB, GiB, TiB)s-ts--terses%ssepss;Print output in terse form with "SEP" as a record separators-es--enums%senumtdefaults3Display enumerated types as numbers instead of texts-fs--forces%sforces3Bypass confirmation prompt for data loss operationss-ws--waits%swaits+Command timeout value in ms (default = 30s)s--headers%sheadersInclude the header with terses-bs%s_asyncsmRun the command async. Instead of waiting for completion. Command will exit(7) and job id written to stdout.s-ss--scripts%sscriptsMDisplaying data in script friendly way with additional information(if exists)i0uN( t_CHILD_OPTION_DST_PREFIXt add_argumentR%targvRR(R\RTtdictt set_defaults(t arg_parsertis_childtprefixt default_dict((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_add_common_optionss\   cCslg|_y1t|jdkr9tj|j|_nWn+tk rg}|jtjkrhqhnX|S(Ni( tsd_pathsR^tvpd83Rt vpd83_searchRR*R t NO_SUPPORT(tlsm_objtlsm_err((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt _add_sd_pathsXs  R$cBseZdZdZRS(cOs tj|||||_dS(s, Class represents an error. N(R2t__init__tmsg(tselftmessagetargstkwargs((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRescCs$dtjjtjd|jfS(Ns%s: error: %s i(tostpathtbasenameR%RR(R((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt__str__ls(t__name__t __module__RR(((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR$ds titemcCsKx!|D]}|j|kr|SqW|rCtd||fndSdS(Ns%s with ID %s not found!(tidR$R!(tltthe_idt friendly_namet raise_errorR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt _get_itemus  cCs*t|}|r|Std|dS(sT Custom value checker for hostname/IP address :param addr: :return: s%s is invalid IP or hostnameN(RxR(taddrRJ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_check_network_hosts tVOLUMEStPOOLStFSt SNAPSHOTStEXPORTStNFS_CLIENT_AUTHt ACCESS_GROUPStSYSTEMStDISKStPLUGINSt TARGET_PORTSt BATTERIEStDEFAULTtTHINtFULLsprovisioning type: s, tCLONEtCOPYt MIRROR_ASYNCt MIRROR_SYNCsreplication type: tENABLEtDISABLEsPolicy: tnames--policyR}sRtchoicesR|tWBtAUTOtWTsWrite cache polices: s' which stand for "write back", "auto", s"write through"s7Can use B, KiB, MiB, GiB, TiB, PiB postfix (IEC sizing)s--sysss System IDsmSearch by System ID. Only supported for: (VOLUMES, POOLS, FS, DISKS, ACCESS_GROUPS, TARGET_PORTS, BATTERIES)s--pools sPool IDs;Search by Pool ID. Only supported for: (VOLUMES, POOLS, FS)s--volss Volume IDsASearch by Volume ID. Only supported for: (VOLUMES, ACCESS_GROUPS)s--fsssFile System IDs=Search by FS ID. Only supported for: (FS, SNAPSHOTS, EXPORTS)s--agssAccess Group IDsGSearch by Access Group ID. Only supported for: (ACCESS_GROUPS, VOLUMES)s--inits s Initiator IDs--snaps s Snapshot IDs--exports s Export IDs --nfs-exportss6Search by NFS Export ID. Only supported for: (EXPORTS)s--disks s.Search by Disk ID. Only supported for: (DISKS)s--sizess--tgtss=Search by target port ID. Only supported for: (TARGET_PORTS)s--pathsLocal disk paths tlistsList records of different typesRs--typesList records of type: s s3 When listing SNAPSHOTS, it requires --fs .stoptionals job-statuss Retrieve information about a jobs--jobss job status idt capabilitiessRetrieves array capabilitiess plugin-infos(Retrieves plugin description and versions volume-createsCreates a volume (logical unit)s--names volume namess--provisioningRsvolume-raid-creates(Creates a RAIDed volume on hardware RAIDss>Free disks for new RAIDed volume. This is repeatable argument.RyRls --raid-types@RAID type for the new RAID group. Should be one of these: %ss --strip-sizes Strip size. svolume-raid-create-caps=Query capability of creating a RAIDed volume on hardware RAIDs volume-deletesDeletes a volume given its ids volume-resizesRe-sizes a volumes s New size. %ssvolume-replicates:Creates a new volume and replicates provided volume to it.ss"The name for New replicated volumes --rep-types s[Pool ID to contain the new volume. By default, new volume will be created in the same pool.svolume-replicate-ranges3Replicates a portion of a volume to existing volumes --src-vols sSource volume ids --dst-vols sDestination volume ids sReplication type: CLONE, COPYs --src-startss>Source volume start block number. This is repeatable argument.s --dst-startssCDestination volume start block number. This is repeatable argument.s--counts s;Number of blocks to replicate. This is repeatable argument.s!volume-replicate-range-block-sizes2Size of each replicated block on a system in bytessvolume-dependantss>Returns True if volume has a dependant child, like replicationsvolume-dependants-rmsRemoves volume dependenciessvolume-access-groups4Lists the access group(s) that have access to volumes volume-masks>Grants access to an access group to a volume, like LUN Maskings volume-unmasks7Revoke the access of specified access group to a volumes volume-enablesEnable block access of a volumesvolume-disables Disable block access of a volumesvolume-raid-infosQuery volume RAID informationsvolume-ident-led-ons!Enable the IDENT LED for a volumesTargeted volume. svolume-ident-led-offs"Disable the IDENT LED for a volumessystem-read-cache-pct-updates,Change the read cache percentage of a systemsTargeted system. s --read-pctsRead cache percentage. spool-member-infos!Query Pool membership informationsaccess-group-createsCreate an access groups s$Human readable name for access groupsaccess-group-adds+Add an initiator into existing access groupsaccess-group-removes.Remove an initiator from existing access groupsaccess-group-deletesDeletes an access groupsaccess-group-volumessBLists the volumes that the access group has been granted access tos iscsi-chaps5Configures iSCSI inbound/outbound CHAP authentications --in-users sInbound chap user names --in-passs sInbound chap passwords --out-users sOutbound chap user names --out-passs sOutbound chap passwords fs-createsCreates a file systems sname of the file systems fs-deletesDelete a filesystems fs-resizesRe-sizes a filesystems fs-exportsExport a filesystem via NFS.s --exportpaths s(NFS server export path. e.g. '/foo/bar'.s --anonuids s%UID(User ID) to map to anonymous users --anongids s&GID(Group ID) to map to anonymous users --auth-types sNFS client authentication types --root-hosts s9The host/IP has root access. This is repeatable argument.s --ro-hosts srThe host/IP has readonly access. This is repeatable argument. At least one '--ro-host' or '--rw-host' is required.s --rw-hosts ssThe host/IP has readwrite access. This is repeatable argument. At least one '--ro-host' or '--rw-host' is required.s fs-unexportsRemove an NFS exportsfs-clonesCreates a file system clones--src-fss s&The ID of existing source file system.s --dst-names s3The name for newly created destination file system.s--backing-snapshots sbacking snapshot idsfs-snap-createsCreates a snapshots s'The human friendly name of new snapshotsfs-snap-deletesDeletes a snapshotsfs-snap-restores;Restores a FS or specified files to previous snapshot states--files skOnly restore provided file Without this argument, all files will be restored This is a repeatable argument.s--fileasssGstore restore file name to another name. This is a repeatable argument.s fs-dependantssHReturns True if filesystem has a child dependency(clone/snapshot) existss-For file check This is a repeatable argument.sfs-dependants-rms Removes file system dependenciessHFile or files to remove dependencies for. This is a repeatable argument.s file-clones,Creates a clone of a file (thin provisioned)s--srcssCsource file to clone (relative path) This is a repeatable argument.s--dstss@Destination file (relative path), this is a repeatable argument.sQuery local disk informationsvolume-cache-infos"Query volume RAM cache informationsvolume-phy-disk-cache-updates)Update volume physical disk cache settingsvolume-read-cache-policy-updatesUpdate volume read cache policys volume-write-cache-policy-updates Update volume write cache policys/Turn on the identification LED for a local disks0Turn off the identification LED for a local disks&Turn on the fault LED for a local disks'Turn off the fault LED for a local disktlsslist --type systemstlpslist --type poolstlvslist --type volumestldslist --type diskstlaslist --type access_groupstlfslist --type fstltslist --type target_portsR4Rptvctvrctvrcctvdtvrtvmtvutvetvitactaatartadtvritvilontvilofftsrcputpmitldltlbslist --type batteriestvcitvpdcutvrcputvwcputldilontldilofftldflontldfloffR"cBseZdZdZdZdZedZedZdZ dZ edZ d Z d Z d Zd Zd ZdZdZdZdZdZdZdZdZdZedZdZdZdZdZdZdZ dZ!dZ"d Z#d!Z$d"Z%ed#Z&d$Z'd%Z(d&Z)d'Z*d(Z+d)Z,d*Z-d+Z.d,Z/d-Z0d.Z1d/Z2d0Z3d1Z4d2Z5d3Z6d4Z7d5Z8d6Z9d7Z:d8Z;d9Z<d:Z=dFd;Z?dFd<Z@d=ZAd>ZBd?ZCd@ZDdAZEdBZFdCZGdDZHdEZIRS(Gs' Command line interface class. cCsd|jjs\|rdnd}td|t}|jdkrKtStdtSntSdS(s1 Give the user a chance to bail. twilltmaysxWarning: You are about to do an operation that %s cause data to be lost! Press [Y|y] to continue, any other key to aborttYsOperation aborted!N(RtforceRRGRVR`R\(RtdeletingRtpressed((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytconfirm_promptTs   cCst}t|dkrdStj}t}|jjr@t}n|jjrUt}n|jjrmtj }ntj |d|d|jj d|jj d|jjd|d|dS(Nit display_wayt flag_humant flag_enumtsplittertflag_with_headertflag_dsp_all_data( R\R^RtDISPLAY_WAY_DEFAULTR`RtseptheadertscripttDISPLAY_WAY_SCRIPTt display_datathumantenum(Rtobjectst display_allRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRks         cCshg}d}tj|}x9|D]1}|j|\}}|jt||q"W|j|dS(Ns<}{>(Rtavailable_pluginsR]RlRR(RtdRtpluginsRptdescRz((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytdisplay_available_pluginss cCsXg}xKtjdD]<}|tkrC|jt|jdq|j|qW|S(sb Walk the command line argument list and build up a new command line with the appropriate substitutions which is then passed to argparse, so that we can avoid adding more sub parsers and do all argument parsing before the need to talk to the library :return copy of command line args with alias expansion: it (R%RtaliasesRkR]Rl(RSRc((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt handle_aliass  cCsCd}x6ttjD]"\}}|dj||7}qW|S(Nscommand aliases: s {0:<18} Alias of '{1}' (tsortedRtitemstformat(RStktv((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytalias_help_textsc CsZtdt}t|dttdddtjddt}t|dt|jdd }xtD]}|j |d d |d d |gdt}|j d }xA|j dgD]-}|d }|d =|j |dt|qW|j d}xV|j dgD]B}|d } |d =t | tsF| f} n|j | |qW|jdt||d jddqmWttjdkr|jtdn||_|jdtj} xt| jD]k\} } | jtr| tt} t| | dks<t| | tkrRt| | | qRqqW| S(s3 Command line interface parameters tadd_helpRt descriptions^The libStorageMgmt command line interface. Run %(prog)s -h for more on each command.tepilogsh Copyright 2012-2018 Red Hat, Inc. Please report bugs to tformatter_classR}tcommandRRtparentsscmd required argumentsRtrequiredscmd optional argumentsRtfunct-RNiN( RR\RR`R"R Rtadd_subparserstcmdst add_parsertadd_argument_grouptgetRt isinstancettupleRtgetattrtreplaceR^R%Rt print_usageR3tparsert parse_argsRtvarsRt startswithRR!tsetattr(Rt parent_parserR t subparserstcmdt sub_parsertgrouptargRtflagst known_argsR R troot_k((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR6sN        $   cCsQ|jjr1t|jjj|jjntdj|jjdS(sD Dump the supported nfs client authentication types s, N(RRRRnR4t export_auth(R((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt!display_nfs_client_authentications %c Csd}d}|jdf|jdf|jdf|jdf|jdf|jdf|jdf|jdff}xJ|D]B}|d ry|rt d ||d fq|\}}qyqyW||fS( Nt system_idtpool_idt volume_idtdisk_idtaccess_group_idtfs_idt nfs_export_idt tgt_port_idis,Search key specified more than once (%s, %s)i( R!R%tpooltvoltdisktagtfst nfs_exportttgtR$(Rt search_keyt search_valuet search_argstsa((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_get_search_key_values$         cCsstj|\}}|jdkrg}|dkr?d}n|dkrt|jj|jddt}|r|jj|}qn=|r|t j krt d|n|jj ||}|j td|Dn|jd krU|d krd}n|r6|tj kr6t d |n|j |jj||n|jd kr|d kryd}n|r|tj krt d|n|j |jj||n|jdkrL|jdkrt dn|r|d krt d|nt|jj|jd}|j |jj|n#|jdkr|dkrpd}n|r|tj krt d|n|j |jj||n|jdkr|rt dn|jn|jdkr|dkr d}n|dkrkt|jj |jddt}|r[|j |jj|S|j gSn(|r|tj krt d|n|j |jj||n|jdkr|rt dn|j |jjn|jdkrj|dkrd}n|r;|tj kr;t d|n|j td|jj||Dn|jd kr|d!krd}n|r|tj krt d"|n|j |jj||n|jd#kr|rt d$n|j ni|jd%kr\|r=|t!j kr=t d&|n|j |jj"||nt d'|jdS((NRR2RR4s Access GroupRs3Search key '%s' is not supported by volume listing.css|]}t|VqdS(N(R(RgR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys sRR1s1Search key '%s' is not supported by pool listing.RR5Rs--fs requireds5Search key '%s' is not supported by snapshot listing.s File SystemRR6s6Search key '%s' is not supported by NFS Export listingRsCNFS client authentication type listing with search is not supportedRRs8Search key '%s' is not supported by Access Group listingRs+System listing with search is not supportedRR3s0Search key '%s' is not supported by disk listingcss|]}t|VqdS(N(R(RgR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys bsRR7s7Search key '%s' is not supported by target port listingRs,Plugins listing with search is not supportedRs3Search key '%s' is not supported by battery listingsunsupported listing type=%s(#R"RCR|RR4t access_groupsR;R\t"volumes_accessible_by_access_groupRtSUPPORTED_SEARCH_KEYSR$tvolumesRRRtpoolsRR<R!t fs_snapshotsRtexportsR/R9taccess_groups_granted_to_volumeRtsystemsRtdisksRt target_portsRRt batteries(RRR?R@tlsm_volstlsm_agR<tlsm_vol((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR s                               cCset|jj|jd}t|j\}}|jj|j|||}|j|gdS(NtSystem( RR4RLR%RMtinittaccess_group_createRR(RRtsystemRIt init_typet access_group((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRU|s  cCsit|jj|jd}t|j\}}|rO|jj|||S|jj|||SdS(Ns Access Group(RR4RDR;RMRTtaccess_group_initiator_addtaccess_group_initiator_delete(RRtopRQRIRW((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_add_rm_access_grp_initscCs |j|j|tgdS(N(RR\R`(RR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytaccess_group_addscCs |j|j|tgdS(N(RR\R\(RR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytaccess_group_removescCsW|jj}t||jd}|jj|}|jtd|DdS(Ns Access Groupcss|]}t|VqdS(N(R(RgR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys s(R4RDRR;RERR(RRtaglR)tvols((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytaccess_group_volumessc CsOt|j\}}|tjkr:td|jn|jjrb|jj rbtdn|jjr|jj rtdn|jjr|jj rtdn|jj r|jj rtdn|jjr|jj r|jjo|jj rtdn|j j ||j|jj|jj|jj dS(Ns$--init "%s" is not a valid iSCSI IQNs--in-user requires --in-passs--in-pass requires --in-users--out-user requires --out-passs--out-pass requires --out-users?out-user and out-password only supported if inbound is supplied( RMRTRtINIT_TYPE_ISCSI_IQNR$Rtin_usertin_passtout_usertout_passR4tiscsi_chap_auth(RRRIRW((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt iscsi_chaps$  cCsAt|jj|jd}|jj|}|j|dS(NR(RR4RGR9RKR(RRR9tgroups((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytvolume_access_groupscCs4|jj}t||jd}|jj|S(Ns Access Group(R4RDRR;taccess_group_delete(RRR_R)((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRkscCsSt|jj|jd}|jtrO|jd|jj|dndS(Ns File Systems fs-delete(RR4R<RR`t _wait_for_itt fs_deleteR!(RRR<((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRmscCset|jj|jd}|jd|jj||j|j|j}|j |gdS(NRs fs-create( RR4RHR8Rlt fs_createRt_sizetsizeR(RRRpR<((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRns  cCst|jj|jd}|j|j}||jkrTttjdn|j t r|j d|jj ||}|j |gndS(Ns File SystemsSpecified size same as currents fs-resize(RR4R<RoRpt total_spaceRR tNO_STATE_CHANGERR\Rlt fs_resizeR(RRR<Rp((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRss cCst|jj|jd}d}|jrQt|jj||jd}n|jd|jj||j |}|j |gdS(NsSource File SystemtSnapshottfs_clone( RR4R<tsrc_fsR!tbacking_snapshotRIRlRutdst_nameR(RRRvtssR<((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRus !cCst|jj|jd}|jjrNt|jj||jd}nd}|jd|jj||j |j |ddS(Ns File SystemRtt fs_file_clone( RR4R<RRwRIR!RlRztsrctdst(RRR<Ry((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt file_clones !cCs/t|}|dkr+td|n|S(Nis$Incorrect size argument format: '%s'(RR$(RWt size_bytes((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRos  cCsW|jjdk r!|jj}nd}|r6d}nd}td|||fdS(NRet SUPPORTEDt UNSUPPORTEDs%s%s%s(RRR!R(RtcaptvalRWR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_cps c Cst|jj|jd}|jj|}t|jj}t|jtj}t j }|j j dk r|j j }nt}x|D]}d||sRcSs|jS(N(t dest_block(Rh((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRsR(tsort(trangesR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_check_overlaps   c Cst|jj|jd}t|jj|jd}t|j}|tjkrmt d|n|j }|j }|j }t | st |t |kot |kn rt dng}xtt |D]} t|| } t|| } t|| } | dkr=t dn| dkrXt dn| dkrst dn| | |jkrt d n| | |jkrt d n|jt| | | qWtj||jtr |jj||||ndS( Ns Source VolumesDestination Volumesinvalid replication type= %ss@Differing numbers of src_start, dest_start, and count parametersis--count: value < 0s--src-start: value < 0s--dst_start: value < 0s#--src-start + --count > source sizes(--dst-start + --count > destination size(RR4RGtsrc_voltdst_volRRRRR$t src_startt dst_starttcountR^RRPt num_of_blocksRlR R"RRR\tvolume_replicate_range( RRR{R|Rt src_startst dst_startstcountsRtbRRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRs>     /    cCs8t|jj|jd}t|jj|dS(NRS(RR4RLR%Rt!volume_replicate_range_block_size(RRRW((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRscCsSt|jj|jd}t|jj|jd}|jj||dS(NRs Access Group(RR4RGR9RDR;t volume_mask(RRR9R;((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRscCsOt|jj|jd}t|jj|jd}|jj||S(Ns Access GroupR(RR4RDR;RGR9t volume_unmask(RRR;R9((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRscCst|jj|jd}|j|j}||j|jkr[tt j dn|j t r|j d|jj||}|jt|gndS(NRsSpecified size same as currenttresize(RR4RGR9RoRpt block_sizeRRR RrRR\Rlt volume_resizeRR(RRR RpR9((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRs cCs2t|jj|jd}|jj|dS(NR(RR4RGR9t volume_enable(RRR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRscCs2t|jj|jd}|jj|dS(NR(RR4RGR9tvolume_disable(RRR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRscCs2t|jj|jd}|jj|dS(Ns NFS Export(RR4RJtexportt export_remove(RRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt fs_unexportsc Cst|jj|jd}t|jdkrWt|jdkrWtdn|jj|j|j |j |j|j|j |j |j d }|j|gdS(Ns File Systemis& please specify --ro-host or --rw-host(RR4R<R^trw_hosttro_hostR$t export_fsRt exportpatht root_hosttanonuidtanongidt auth_typeR!R(RRR<R((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt fs_export!s  cCs>t|jj|jd}|jj|}t|dS(NR(RR4RGR9tvolume_child_dependencyR(RRR RS((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytvolume_dependants6scCsAt|jj|jd}|jd|jj|ddS(NRsvolume-dependant-rm(RR4RGR9Rltvolume_child_dependency_rmR!(RRR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytvolume_dependants_rm<s cCsJt|jj|jd}|jt|j|jj|gdS(NR(RR4RGR9RRRtvolume_raid_info(RRRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRAscCsJt|jj|jd}|jt|j|jj|gdS(NR(RR4RHR8RRRtpool_member_info(RRtlsm_pool((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRHscCs\tj|j}|jj}g|D]}|j|jkr(|^q(}t|t|jkrtt j ddj t |jt d|Dng|D]}|j tj@s|j^q}t|dkrtt jddj |n|jr!t|j}n tj}|jt|jj|j|||gdS(NsDisk ID %s not founds, css|]}|jVqdS(N(R(RgR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys XsisDisk %s is not free(Rtraid_type_str_to_lsmt raid_typeR4RMRR:R^RR tNOT_FOUND_DISKRntsettstatusRt STATUS_FREEt DISK_NOT_FREEt strip_sizeRRtVCR_STRIP_SIZE_DEFAULTRRtvolume_raid_createR(RRRt all_lsm_disksRt lsm_diskst busy_disksR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyROs*+3    cCsJt|jj|jd}|jt|j|jj|gdS(NRS(RR4RLR%RRRtvolume_raid_create_cap_get(RRtlsm_sys((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytvolume_raid_create_caplscCs2t|jj|jd}|jj|dS(NR(RR4RGR9tvolume_ident_led_on(RRt lsm_volume((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRqscCs2t|jj|jd}|jj|dS(NR(RR4RGR9tvolume_ident_led_off(RRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRvscCst|jj|jd}yt|j}Wn+tk r^}ttj t |nX|jj ||t|jj|jd}|j |gdS(NRS( RR4RLR%R_tread_pctRQRR tINVALID_ARGUMENTR(tsystem_read_cache_pct_updateR(RRt lsm_systemRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR{scCsDt|jj|jd}|jj||j}t|dS(Ns File System(RR4R<tfs_child_dependencyR R(RRR<RS((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt fs_dependantsscCsGt|jj|jd}|jd|jj||jddS(Ns File Systemsfs-dependants-rm(RR4R<Rltfs_child_dependency_rmR R!(RRR<((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytfs_dependants_rms    c Csd}tjjdd}tjj|s2dSt|}x|D]}|jjdriqHnyTg|jddD]}|j^q\}}||krt |||nWqHt k rqHXqHWWdQXdS( so Set uri from config file. Will be overridden by cmdline option or env var if present. turit~s/.lsmcliNt#t=i(suri( RRt expandusertexiststopentlstripR#R]tstripR$RQ(Rtallowed_config_optionst config_pathtftlineRhRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_read_configfiles 1  cCs)|jjjjddtkr%tStS(sU Return True if current command is one of _CONNECTION_FREE_COMMANDS. RNR(RRRRt_CONNECTION_FREE_COMMANDSR`R\(R((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytis_connection_free_cmds cCsd|_d|_d|_d|_|j|_d|_t|jj |_ |j sj|j dkryt dn|j rdS|j tjddk rtjd|_ntjd|_|jjdk r|jj|_n|jdkrGd|jkr8|jjdkr8d|_d|_qGt dn|jjretj|_n|jdk rt|j}|d dkrt d qndS( Nis0[-w|--wait] requires a non-zero positive integert LSMCLI_URItLSMCLI_PASSWORDR|Rssim://s"--uri missing or export LSMCLI_URItusernames+password specified with no user name in uri(R!RR4R t unknown_argsR6RtcleanupR_twaitttmoR$RRRtgetenvtpasswordR|tprompttgetpassR (Rtu((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRs8       !   cCs0|jr|jn|r,tj|ndS(N(R R%R3(Rtec((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR1s  cCs|jr"|jj|jn|rkt||_|jj|j|j|j|jj |_ nOtt |j|j|j|_t j drtdn|jj|_ |jj|j|jdS(s- Process the parsed command. tLSM_DEBUG_PLUGINs8Attach debugger to plug-in, press when ready...N(RRRR R4tplugin_registerRRR tplugin_unregisterR RRRtinputtcloseR1(RR6((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR#s $ c Csg}itjd6tjd6tjd6tjd6tjd6tjd6tjd6}x%tjD]}idd6t j d6t j d6dd6t j d6t j d6t jd6}x|jD]v}y|||||  p                  2                    /  *     (RRR(RRRR(lRR%RRsRR?R=targparseRRRtsixtlsmRRRRRRR R R R R RRRRRRRtlsm.lsmcli.data_displayRRRRRRRRRRRtPY3R_RPt collectionsRt ImportErrort ordereddictR!R:RGRMRORTRRXRdRqRxR\RRR2R$R`RRt list_choicestprovision_typesRntprovision_helptreplicate_typestreplicate_helpt policy_typest policy_helpRt policy_opttwrite_cache_policy_typestwrite_cache_policy_helptwrite_cache_policy_optt size_helpt sys_id_opttcopytsys_id_filter_optt pool_id_opttpool_id_filter_optt vol_id_opttvol_id_filter_optt fs_id_opttfs_id_filter_optt ag_id_opttag_id_filter_optt init_id_optt snap_id_optt export_id_opttnfs_export_id_filter_opttdisk_id_filter_opttsize_optttgt_id_filter_opttlocal_disk_path_opttVOL_CREATE_RAID_TYPES_STRtANON_UID_GID_NARRtobjectR"(((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyts        vF     -     *  G                                                                            lsmcli/cmdline.pyo000064400000170163147576505410010221 0ustar00 /P`cK@sddlZddlZddlZddlZddlZddlZddlZddlmZm Z ddlm Z ddl Z ddl m Z mZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZddlm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)dddd d gZ*e j+rie,Z-nydd l.m/Z/Wn!e0k rdd l1m/Z/nXdd Z3d Z4dZ5dZ6dZ7dZ8dZ9dZ:dZ;dZ<e=dZ>dZ?de@fdYZAdeBdZCdZDdddd d!d"d#d$d%d&d'd(g ZEdpZFd,d-jGeFZHdqZId2d-jGeIZJd3d4gZKd5d-jGeKZLeMd6d7d8d9d:eLd;eKd<e9ZNd=d>d?gZOd@d-jGeOdAdBZPeMd6d7d8d9d:ePd;eOd<e9ZQdCZReMd6dDd8dEd:dFZSeSjTZUdGeUd:dqeMeegeMd6d d:d?dqeMeegeMd6d d:d@dqeMeegf3ZheMdAdBdCdDdEdFdGdHdIdJdKdLdMdNdOd}dPddQddRddSddTddUddVddWddXddYddZdd[dd\dd]dd^dd_dd`ddaddbddcddddedfd5dgd7dhd9did;djddkddld dmd %ZidnejfdoYZkdS(riN(tArgumentParsertArgumentTypeError(tRawTextHelpFormatter(tClienttPooltVERSIONtLsmErrortDisktVolumet JobStatust ErrorNumbert BlockRanget uri_parsetProxytsize_human_2_size_bytest AccessGroupt FileSystemt NfsExportt TargetPortt LocalDisktBattery( t DisplayDatatPlugDatatouttvol_provision_str_to_typetvol_rep_type_str_to_typetVolumeRAIDInfot PoolRAIDInfotVcrCapt LocalDiskInfotVolumeRAMCacheInfoslocal-disk-listslocal-disk-ident-led-onslocal-disk-ident-led-offslocal-disk-fault-led-onslocal-disk-fault-led-off(t OrderedDictcCsbd}d}zyt}|j|Wntk rg}tjjt|tjjd}nt k r}tjjt|dtjj|j t j krd}qd}n]t k rd}nGtk r}|j }n,ddl}|jd tjd}nXWd|rPy|j|WqPtk rLqPXntj|XdS( s+ Common command line code, called. iis i iiiNtfile(tNonetCmdLinetprocesstArgErrortsyststderrtwritetstrtflushRtcodeR tPERMISSION_DENIEDtKeyboardInterruptt SystemExitt tracebackt print_exctstdouttshutdownt Exceptiontexit(tcterr_exittclitaetletseR.((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytcmd_line_wrapper;s<           cCshtjj}tj|}z,tjtjjtjjd}Wdtj|tj |X|S(Ni( R%tstdintfilenottermiost tcgetattrtttytsetrawtreadt tcsetattrt TCSADRAIN(tfdtprevtch((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytgetchhscCs<tj|\}}}|r(||fStd|dS(s If init_id is a WWPN, convert it into LSM standard version: (?:[0-9a-f]{2}:){7}[0-9a-f]{2} Return (converted_init_id, lsm_init_type) s,--init "%s" is not a valid WWPN or iSCSI IQNN(Rtinitiator_id_verifyR$(tinit_idtvalidtconverted_init_typetconverted_init_id((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytparse_convert_initss cCs6tj|\}}}|r"|Std|dS(s Call back from validating an initiator :param init_id: Initiator to validate :return: Value of initiator or raises an exception s!"%s" is invalid WWPN or iSCSI IQNN(RRHR(RIRJt_RL((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt _check_initscCs^y6t|d}|dkr1td|n|SWn!tk rYtd|nXdS(s Call back for validating a positive integer :param num: Number string to check :return: Numeric value, else exception i is,invalid: require positive integer value '%d's*invalid: not a positive integer value '%s'N(tlongRt ValueError(tnumtrc((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_check_positive_integers  tchild_cCs |jS(N(tupper(ts((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_upperscCs|s tS|jd}t|dkr/tSd|kr?tSx|D]}dt|koidknsrtSt|dkr|ddkrtSyt|dd krtSWqFtk rtSXqFWtS( s Check if a string represents a valid ip4 address :param address: String representing address :return: True if valid address, else false t.it/iiit0i i(tFalsetsplittlentintRQtTrue(taddresstpartsti((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_valid_ip4_addresss$  ""  cskdt}|stSd|kr&tSt|jddkrEtS|jd}t|dksxt|dkr|tSd|d krt|jsd GHtS|jd d gnd|krg|D]}|d kr|^q}|jd t}n|rt|d ks.t|d krgtd|Doftfdd j |DStS(s Check if a string represents a valid ipv6 address :param address: String representing address :return: True if valid address, else false sABCDEFabcdef0123456789:RZs::it:ii RYisNot valid ipv suffixR[ticss!|]}t|dkVqdS(iN(R^(t.0tx((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys sc3s|]}|kVqdS(N((RgRh(tallowed(s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys s( R\R^R]RdtpoptextendtappendR`talltjoin(Rat has_zerosRbtp((Ris6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_valid_ip6_addresss0 $ %  *#cstjdtjtjd}t|r4tSt|rDtSt|dkrZtS|j|rmtS|ddkr|d }nt fd|j dDS(s Checks to see if the supplied string is a valid ip4/6 or hostname :param ip_hn: String representing address user inputted :return: True if valid IP address or hostname s(?!-)[A-Z0-9-]{1,63}(?s( tretcompilet IGNORECASERdR`RqR^R\RrRmR](tip_hnt digits_only((Ris6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_is_valid_network_names   c Csd}|rt}n|jddddddtjdtf|jdd dd d td d dd|dd|jdddddd|dd|jdddddd|dd|jdddd dd|d ddd|jd d!dddd"|d#tdd$|jd%d&dddd'|d#tdd(|jd)d*dd dd+|dd,d t|jd-dddd.|dd/|jd0dddd1|d#tdd2|jd3d4dddd5|d#tdd6|rt}d7|d+|<|j |nd8S(9s As https://bugs.python.org/issue23058 indicate, argument parser should not have subparser sharing the same argument and destination. For subparser, we add common options as 'child_xxx' destination. For default value, False is the only allowed default value in root. Rfs-vs --versiontactiontversions%s %sis-us--uritstorettypetmetavarstdests%surithelps,Uniform resource identifier (env LSMCLI_URI)s-Ps--promptt store_trues%sprompts)Prompt for password (env LSMCLI_PASSWORD)s-Hs--humans%shumans:Print sizes in human readable format (e.g., MiB, GiB, TiB)s-ts--terses%ssepss;Print output in terse form with "SEP" as a record separators-es--enums%senumtdefaults3Display enumerated types as numbers instead of texts-fs--forces%sforces3Bypass confirmation prompt for data loss operationss-ws--waits%swaits+Command timeout value in ms (default = 30s)s--headers%sheadersInclude the header with terses-bs%s_asyncsmRun the command async. Instead of waiting for completion. Command will exit(7) and job id written to stdout.s-ss--scripts%sscriptsMDisplaying data in script friendly way with additional information(if exists)i0uN( t_CHILD_OPTION_DST_PREFIXt add_argumentR%targvRR(R\RTtdictt set_defaults(t arg_parsertis_childtprefixt default_dict((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_add_common_optionss\   cCslg|_y1t|jdkr9tj|j|_nWn+tk rg}|jtjkrhqhnX|S(Ni( tsd_pathsR^tvpd83Rt vpd83_searchRR*R t NO_SUPPORT(tlsm_objtlsm_err((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt _add_sd_pathsXs  R$cBseZdZdZRS(cOs tj|||||_dS(s, Class represents an error. N(R2t__init__tmsg(tselftmessagetargstkwargs((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRescCs$dtjjtjd|jfS(Ns%s: error: %s i(tostpathtbasenameR%RR(R((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt__str__ls(t__name__t __module__RR(((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR$ds titemcCsKx!|D]}|j|kr|SqW|rCtd||fndSdS(Ns%s with ID %s not found!(tidR$R!(tltthe_idt friendly_namet raise_errorR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt _get_itemus  cCs*t|}|r|Std|dS(sT Custom value checker for hostname/IP address :param addr: :return: s%s is invalid IP or hostnameN(RxR(taddrRJ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_check_network_hosts tVOLUMEStPOOLStFSt SNAPSHOTStEXPORTStNFS_CLIENT_AUTHt ACCESS_GROUPStSYSTEMStDISKStPLUGINSt TARGET_PORTSt BATTERIEStDEFAULTtTHINtFULLsprovisioning type: s, tCLONEtCOPYt MIRROR_ASYNCt MIRROR_SYNCsreplication type: tENABLEtDISABLEsPolicy: tnames--policyR}sRtchoicesR|tWBtAUTOtWTsWrite cache polices: s' which stand for "write back", "auto", s"write through"s7Can use B, KiB, MiB, GiB, TiB, PiB postfix (IEC sizing)s--sysss System IDsmSearch by System ID. Only supported for: (VOLUMES, POOLS, FS, DISKS, ACCESS_GROUPS, TARGET_PORTS, BATTERIES)s--pools sPool IDs;Search by Pool ID. Only supported for: (VOLUMES, POOLS, FS)s--volss Volume IDsASearch by Volume ID. Only supported for: (VOLUMES, ACCESS_GROUPS)s--fsssFile System IDs=Search by FS ID. Only supported for: (FS, SNAPSHOTS, EXPORTS)s--agssAccess Group IDsGSearch by Access Group ID. Only supported for: (ACCESS_GROUPS, VOLUMES)s--inits s Initiator IDs--snaps s Snapshot IDs--exports s Export IDs --nfs-exportss6Search by NFS Export ID. Only supported for: (EXPORTS)s--disks s.Search by Disk ID. Only supported for: (DISKS)s--sizess--tgtss=Search by target port ID. Only supported for: (TARGET_PORTS)s--pathsLocal disk paths tlistsList records of different typesRs--typesList records of type: s s3 When listing SNAPSHOTS, it requires --fs .stoptionals job-statuss Retrieve information about a jobs--jobss job status idt capabilitiessRetrieves array capabilitiess plugin-infos(Retrieves plugin description and versions volume-createsCreates a volume (logical unit)s--names volume namess--provisioningRsvolume-raid-creates(Creates a RAIDed volume on hardware RAIDss>Free disks for new RAIDed volume. This is repeatable argument.RyRls --raid-types@RAID type for the new RAID group. Should be one of these: %ss --strip-sizes Strip size. svolume-raid-create-caps=Query capability of creating a RAIDed volume on hardware RAIDs volume-deletesDeletes a volume given its ids volume-resizesRe-sizes a volumes s New size. %ssvolume-replicates:Creates a new volume and replicates provided volume to it.ss"The name for New replicated volumes --rep-types s[Pool ID to contain the new volume. By default, new volume will be created in the same pool.svolume-replicate-ranges3Replicates a portion of a volume to existing volumes --src-vols sSource volume ids --dst-vols sDestination volume ids sReplication type: CLONE, COPYs --src-startss>Source volume start block number. This is repeatable argument.s --dst-startssCDestination volume start block number. This is repeatable argument.s--counts s;Number of blocks to replicate. This is repeatable argument.s!volume-replicate-range-block-sizes2Size of each replicated block on a system in bytessvolume-dependantss>Returns True if volume has a dependant child, like replicationsvolume-dependants-rmsRemoves volume dependenciessvolume-access-groups4Lists the access group(s) that have access to volumes volume-masks>Grants access to an access group to a volume, like LUN Maskings volume-unmasks7Revoke the access of specified access group to a volumes volume-enablesEnable block access of a volumesvolume-disables Disable block access of a volumesvolume-raid-infosQuery volume RAID informationsvolume-ident-led-ons!Enable the IDENT LED for a volumesTargeted volume. svolume-ident-led-offs"Disable the IDENT LED for a volumessystem-read-cache-pct-updates,Change the read cache percentage of a systemsTargeted system. s --read-pctsRead cache percentage. spool-member-infos!Query Pool membership informationsaccess-group-createsCreate an access groups s$Human readable name for access groupsaccess-group-adds+Add an initiator into existing access groupsaccess-group-removes.Remove an initiator from existing access groupsaccess-group-deletesDeletes an access groupsaccess-group-volumessBLists the volumes that the access group has been granted access tos iscsi-chaps5Configures iSCSI inbound/outbound CHAP authentications --in-users sInbound chap user names --in-passs sInbound chap passwords --out-users sOutbound chap user names --out-passs sOutbound chap passwords fs-createsCreates a file systems sname of the file systems fs-deletesDelete a filesystems fs-resizesRe-sizes a filesystems fs-exportsExport a filesystem via NFS.s --exportpaths s(NFS server export path. e.g. '/foo/bar'.s --anonuids s%UID(User ID) to map to anonymous users --anongids s&GID(Group ID) to map to anonymous users --auth-types sNFS client authentication types --root-hosts s9The host/IP has root access. This is repeatable argument.s --ro-hosts srThe host/IP has readonly access. This is repeatable argument. At least one '--ro-host' or '--rw-host' is required.s --rw-hosts ssThe host/IP has readwrite access. This is repeatable argument. At least one '--ro-host' or '--rw-host' is required.s fs-unexportsRemove an NFS exportsfs-clonesCreates a file system clones--src-fss s&The ID of existing source file system.s --dst-names s3The name for newly created destination file system.s--backing-snapshots sbacking snapshot idsfs-snap-createsCreates a snapshots s'The human friendly name of new snapshotsfs-snap-deletesDeletes a snapshotsfs-snap-restores;Restores a FS or specified files to previous snapshot states--files skOnly restore provided file Without this argument, all files will be restored This is a repeatable argument.s--fileasssGstore restore file name to another name. This is a repeatable argument.s fs-dependantssHReturns True if filesystem has a child dependency(clone/snapshot) existss-For file check This is a repeatable argument.sfs-dependants-rms Removes file system dependenciessHFile or files to remove dependencies for. This is a repeatable argument.s file-clones,Creates a clone of a file (thin provisioned)s--srcssCsource file to clone (relative path) This is a repeatable argument.s--dstss@Destination file (relative path), this is a repeatable argument.sQuery local disk informationsvolume-cache-infos"Query volume RAM cache informationsvolume-phy-disk-cache-updates)Update volume physical disk cache settingsvolume-read-cache-policy-updatesUpdate volume read cache policys volume-write-cache-policy-updates Update volume write cache policys/Turn on the identification LED for a local disks0Turn off the identification LED for a local disks&Turn on the fault LED for a local disks'Turn off the fault LED for a local disktlsslist --type systemstlpslist --type poolstlvslist --type volumestldslist --type diskstlaslist --type access_groupstlfslist --type fstltslist --type target_portsR4Rptvctvrctvrcctvdtvrtvmtvutvetvitactaatartadtvritvilontvilofftsrcputpmitldltlbslist --type batteriestvcitvpdcutvrcputvwcputldilontldilofftldflontldfloffR"cBseZdZdZdZdZedZedZdZ dZ edZ d Z d Z d Zd Zd ZdZdZdZdZdZdZdZdZdZedZdZdZdZdZdZdZ dZ!dZ"d Z#d!Z$d"Z%ed#Z&d$Z'd%Z(d&Z)d'Z*d(Z+d)Z,d*Z-d+Z.d,Z/d-Z0d.Z1d/Z2d0Z3d1Z4d2Z5d3Z6d4Z7d5Z8d6Z9d7Z:d8Z;d9Z<d:Z=dFd;Z?dFd<Z@d=ZAd>ZBd?ZCd@ZDdAZEdBZFdCZGdDZHdEZIRS(Gs' Command line interface class. cCsd|jjs\|rdnd}td|t}|jdkrKtStdtSntSdS(s1 Give the user a chance to bail. twilltmaysxWarning: You are about to do an operation that %s cause data to be lost! Press [Y|y] to continue, any other key to aborttYsOperation aborted!N(RtforceRRGRVR`R\(RtdeletingRtpressed((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytconfirm_promptTs   cCst}t|dkrdStj}t}|jjr@t}n|jjrUt}n|jjrmtj }ntj |d|d|jj d|jj d|jjd|d|dS(Nit display_wayt flag_humant flag_enumtsplittertflag_with_headertflag_dsp_all_data( R\R^RtDISPLAY_WAY_DEFAULTR`RtseptheadertscripttDISPLAY_WAY_SCRIPTt display_datathumantenum(Rtobjectst display_allRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRks         cCshg}d}tj|}x9|D]1}|j|\}}|jt||q"W|j|dS(Ns<}{>(Rtavailable_pluginsR]RlRR(RtdRtpluginsRptdescRz((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytdisplay_available_pluginss cCsXg}xKtjdD]<}|tkrC|jt|jdq|j|qW|S(sb Walk the command line argument list and build up a new command line with the appropriate substitutions which is then passed to argparse, so that we can avoid adding more sub parsers and do all argument parsing before the need to talk to the library :return copy of command line args with alias expansion: it (R%RtaliasesRkR]Rl(RSRc((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt handle_aliass  cCsCd}x6ttjD]"\}}|dj||7}qW|S(Nscommand aliases: s {0:<18} Alias of '{1}' (tsortedRtitemstformat(RStktv((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytalias_help_textsc CsZtdt}t|dttdddtjddt}t|dt|jdd }xtD]}|j |d d |d d |gdt}|j d }xA|j dgD]-}|d }|d =|j |dt|qW|j d}xV|j dgD]B}|d } |d =t | tsF| f} n|j | |qW|jdt||d jddqmWttjdkr|jtdn||_|jdtj} xt| jD]k\} } | jtr| tt} t| | dks<t| | tkrRt| | | qRqqW| S(s3 Command line interface parameters tadd_helpRt descriptions^The libStorageMgmt command line interface. Run %(prog)s -h for more on each command.tepilogsh Copyright 2012-2018 Red Hat, Inc. Please report bugs to tformatter_classR}tcommandRRtparentsscmd required argumentsRtrequiredscmd optional argumentsRtfunct-RNiN( RR\RR`R"R Rtadd_subparserstcmdst add_parsertadd_argument_grouptgetRt isinstancettupleRtgetattrtreplaceR^R%Rt print_usageR3tparsert parse_argsRtvarsRt startswithRR!tsetattr(Rt parent_parserR t subparserstcmdt sub_parsertgrouptargRtflagst known_argsR R troot_k((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR6sN        $   cCsQ|jjr1t|jjj|jjntdj|jjdS(sD Dump the supported nfs client authentication types s, N(RRRRnR4t export_auth(R((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt!display_nfs_client_authentications %c Csd}d}|jdf|jdf|jdf|jdf|jdf|jdf|jdf|jdff}xJ|D]B}|d ry|rt d ||d fq|\}}qyqyW||fS( Nt system_idtpool_idt volume_idtdisk_idtaccess_group_idtfs_idt nfs_export_idt tgt_port_idis,Search key specified more than once (%s, %s)i( R!R%tpooltvoltdisktagtfst nfs_exportttgtR$(Rt search_keyt search_valuet search_argstsa((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_get_search_key_values$         cCsstj|\}}|jdkrg}|dkr?d}n|dkrt|jj|jddt}|r|jj|}qn=|r|t j krt d|n|jj ||}|j td|Dn|jd krU|d krd}n|r6|tj kr6t d |n|j |jj||n|jd kr|d kryd}n|r|tj krt d|n|j |jj||n|jdkrL|jdkrt dn|r|d krt d|nt|jj|jd}|j |jj|n#|jdkr|dkrpd}n|r|tj krt d|n|j |jj||n|jdkr|rt dn|jn|jdkr|dkr d}n|dkrkt|jj |jddt}|r[|j |jj|S|j gSn(|r|tj krt d|n|j |jj||n|jdkr|rt dn|j |jjn|jdkrj|dkrd}n|r;|tj kr;t d|n|j td|jj||Dn|jd kr|d!krd}n|r|tj krt d"|n|j |jj||n|jd#kr|rt d$n|j ni|jd%kr\|r=|t!j kr=t d&|n|j |jj"||nt d'|jdS((NRR2RR4s Access GroupRs3Search key '%s' is not supported by volume listing.css|]}t|VqdS(N(R(RgR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys sRR1s1Search key '%s' is not supported by pool listing.RR5Rs--fs requireds5Search key '%s' is not supported by snapshot listing.s File SystemRR6s6Search key '%s' is not supported by NFS Export listingRsCNFS client authentication type listing with search is not supportedRRs8Search key '%s' is not supported by Access Group listingRs+System listing with search is not supportedRR3s0Search key '%s' is not supported by disk listingcss|]}t|VqdS(N(R(RgR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys bsRR7s7Search key '%s' is not supported by target port listingRs,Plugins listing with search is not supportedRs3Search key '%s' is not supported by battery listingsunsupported listing type=%s(#R"RCR|RR4t access_groupsR;R\t"volumes_accessible_by_access_groupRtSUPPORTED_SEARCH_KEYSR$tvolumesRRRtpoolsRR<R!t fs_snapshotsRtexportsR/R9taccess_groups_granted_to_volumeRtsystemsRtdisksRt target_portsRRt batteries(RRR?R@tlsm_volstlsm_agR<tlsm_vol((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR s                               cCset|jj|jd}t|j\}}|jj|j|||}|j|gdS(NtSystem( RR4RLR%RMtinittaccess_group_createRR(RRtsystemRIt init_typet access_group((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRU|s  cCsit|jj|jd}t|j\}}|rO|jj|||S|jj|||SdS(Ns Access Group(RR4RDR;RMRTtaccess_group_initiator_addtaccess_group_initiator_delete(RRtopRQRIRW((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_add_rm_access_grp_initscCs |j|j|tgdS(N(RR\R`(RR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytaccess_group_addscCs |j|j|tgdS(N(RR\R\(RR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytaccess_group_removescCsW|jj}t||jd}|jj|}|jtd|DdS(Ns Access Groupcss|]}t|VqdS(N(R(RgR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys s(R4RDRR;RERR(RRtaglR)tvols((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytaccess_group_volumessc CsOt|j\}}|tjkr:td|jn|jjrb|jj rbtdn|jjr|jj rtdn|jjr|jj rtdn|jj r|jj rtdn|jjr|jj r|jjo|jj rtdn|j j ||j|jj|jj|jj dS(Ns$--init "%s" is not a valid iSCSI IQNs--in-user requires --in-passs--in-pass requires --in-users--out-user requires --out-passs--out-pass requires --out-users?out-user and out-password only supported if inbound is supplied( RMRTRtINIT_TYPE_ISCSI_IQNR$Rtin_usertin_passtout_usertout_passR4tiscsi_chap_auth(RRRIRW((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt iscsi_chaps$  cCsAt|jj|jd}|jj|}|j|dS(NR(RR4RGR9RKR(RRR9tgroups((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytvolume_access_groupscCs4|jj}t||jd}|jj|S(Ns Access Group(R4RDRR;taccess_group_delete(RRR_R)((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRkscCsSt|jj|jd}|jtrO|jd|jj|dndS(Ns File Systems fs-delete(RR4R<RR`t _wait_for_itt fs_deleteR!(RRR<((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRmscCset|jj|jd}|jd|jj||j|j|j}|j |gdS(NRs fs-create( RR4RHR8Rlt fs_createRt_sizetsizeR(RRRpR<((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRns  cCst|jj|jd}|j|j}||jkrTttjdn|j t r|j d|jj ||}|j |gndS(Ns File SystemsSpecified size same as currents fs-resize(RR4R<RoRpt total_spaceRR tNO_STATE_CHANGERR\Rlt fs_resizeR(RRR<Rp((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRss cCst|jj|jd}d}|jrQt|jj||jd}n|jd|jj||j |}|j |gdS(NsSource File SystemtSnapshottfs_clone( RR4R<tsrc_fsR!tbacking_snapshotRIRlRutdst_nameR(RRRvtssR<((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRus !cCst|jj|jd}|jjrNt|jj||jd}nd}|jd|jj||j |j |ddS(Ns File SystemRtt fs_file_clone( RR4R<RRwRIR!RlRztsrctdst(RRR<Ry((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt file_clones !cCs/t|}|dkr+td|n|S(Nis$Incorrect size argument format: '%s'(RR$(RWt size_bytes((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRos  cCsW|jjdk r!|jj}nd}|r6d}nd}td|||fdS(NRet SUPPORTEDt UNSUPPORTEDs%s%s%s(RRR!R(RtcaptvalRWR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_cps c Cst|jj|jd}|jj|}t|jj}t|jtj}t j }|j j dk r|j j }nt}x|D]}d||sRcSs|jS(N(t dest_block(Rh((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRsR(tsort(trangesR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_check_overlaps   c Cst|jj|jd}t|jj|jd}t|j}|tjkrmt d|n|j }|j }|j }t | st |t |kot |kn rt dng}xtt |D]} t|| } t|| } t|| } | dkr=t dn| dkrXt dn| dkrst dn| | |jkrt d n| | |jkrt d n|jt| | | qWtj||jtr |jj||||ndS( Ns Source VolumesDestination Volumesinvalid replication type= %ss@Differing numbers of src_start, dest_start, and count parametersis--count: value < 0s--src-start: value < 0s--dst_start: value < 0s#--src-start + --count > source sizes(--dst-start + --count > destination size(RR4RGtsrc_voltdst_volRRRRR$t src_startt dst_starttcountR^RRPt num_of_blocksRlR R"RRR\tvolume_replicate_range( RRR{R|Rt src_startst dst_startstcountsRtbRRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRs>     /    cCs8t|jj|jd}t|jj|dS(NRS(RR4RLR%Rt!volume_replicate_range_block_size(RRRW((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRscCsSt|jj|jd}t|jj|jd}|jj||dS(NRs Access Group(RR4RGR9RDR;t volume_mask(RRR9R;((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRscCsOt|jj|jd}t|jj|jd}|jj||S(Ns Access GroupR(RR4RDR;RGR9t volume_unmask(RRR;R9((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRscCst|jj|jd}|j|j}||j|jkr[tt j dn|j t r|j d|jj||}|jt|gndS(NRsSpecified size same as currenttresize(RR4RGR9RoRpt block_sizeRRR RrRR\Rlt volume_resizeRR(RRR RpR9((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRs cCs2t|jj|jd}|jj|dS(NR(RR4RGR9t volume_enable(RRR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRscCs2t|jj|jd}|jj|dS(NR(RR4RGR9tvolume_disable(RRR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRscCs2t|jj|jd}|jj|dS(Ns NFS Export(RR4RJtexportt export_remove(RRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt fs_unexportsc Cst|jj|jd}t|jdkrWt|jdkrWtdn|jj|j|j |j |j|j|j |j |j d }|j|gdS(Ns File Systemis& please specify --ro-host or --rw-host(RR4R<R^trw_hosttro_hostR$t export_fsRt exportpatht root_hosttanonuidtanongidt auth_typeR!R(RRR<R((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt fs_export!s  cCs>t|jj|jd}|jj|}t|dS(NR(RR4RGR9tvolume_child_dependencyR(RRR RS((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytvolume_dependants6scCsAt|jj|jd}|jd|jj|ddS(NRsvolume-dependant-rm(RR4RGR9Rltvolume_child_dependency_rmR!(RRR ((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytvolume_dependants_rm<s cCsJt|jj|jd}|jt|j|jj|gdS(NR(RR4RGR9RRRtvolume_raid_info(RRRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRAscCsJt|jj|jd}|jt|j|jj|gdS(NR(RR4RHR8RRRtpool_member_info(RRtlsm_pool((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRHscCs\tj|j}|jj}g|D]}|j|jkr(|^q(}t|t|jkrtt j ddj t |jt d|Dng|D]}|j tj@s|j^q}t|dkrtt jddj |n|jr!t|j}n tj}|jt|jj|j|||gdS(NsDisk ID %s not founds, css|]}|jVqdS(N(R(RgR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pys XsisDisk %s is not free(Rtraid_type_str_to_lsmt raid_typeR4RMRR:R^RR tNOT_FOUND_DISKRntsettstatusRt STATUS_FREEt DISK_NOT_FREEt strip_sizeRRtVCR_STRIP_SIZE_DEFAULTRRtvolume_raid_createR(RRRt all_lsm_disksRt lsm_diskst busy_disksR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyROs*+3    cCsJt|jj|jd}|jt|j|jj|gdS(NRS(RR4RLR%RRRtvolume_raid_create_cap_get(RRtlsm_sys((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytvolume_raid_create_caplscCs2t|jj|jd}|jj|dS(NR(RR4RGR9tvolume_ident_led_on(RRt lsm_volume((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRqscCs2t|jj|jd}|jj|dS(NR(RR4RGR9tvolume_ident_led_off(RRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRvscCst|jj|jd}yt|j}Wn+tk r^}ttj t |nX|jj ||t|jj|jd}|j |gdS(NRS( RR4RLR%R_tread_pctRQRR tINVALID_ARGUMENTR(tsystem_read_cache_pct_updateR(RRt lsm_systemRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR{scCsDt|jj|jd}|jj||j}t|dS(Ns File System(RR4R<tfs_child_dependencyR R(RRR<RS((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt fs_dependantsscCsGt|jj|jd}|jd|jj||jddS(Ns File Systemsfs-dependants-rm(RR4R<Rltfs_child_dependency_rmR R!(RRR<((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytfs_dependants_rms    c Csd}tjjdd}tjj|s2dSt|}x|D]}|jjdriqHnyTg|jddD]}|j^q\}}||krt |||nWqHt k rqHXqHWWdQXdS( so Set uri from config file. Will be overridden by cmdline option or env var if present. turit~s/.lsmcliNt#t=i(suri( RRt expandusertexiststopentlstripR#R]tstripR$RQ(Rtallowed_config_optionst config_pathtftlineRhRR((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyt_read_configfiles 1  cCs)|jjjjddtkr%tStS(sU Return True if current command is one of _CONNECTION_FREE_COMMANDS. RNR(RRRRt_CONNECTION_FREE_COMMANDSR`R\(R((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pytis_connection_free_cmds cCsd|_d|_d|_d|_|j|_d|_t|jj |_ |j sj|j dkryt dn|j rdS|j tjddk rtjd|_ntjd|_|jjdk r|jj|_n|jdkrGd|jkr8|jjdkr8d|_d|_qGt dn|jjretj|_n|jdk rt|j}|d dkrt d qndS( Nis0[-w|--wait] requires a non-zero positive integert LSMCLI_URItLSMCLI_PASSWORDR|Rssim://s"--uri missing or export LSMCLI_URItusernames+password specified with no user name in uri(R!RR4R t unknown_argsR6RtcleanupR_twaitttmoR$RRRtgetenvtpasswordR|tprompttgetpassR (Rtu((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyRs8       !   cCs0|jr|jn|r,tj|ndS(N(R R%R3(Rtec((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR1s  cCs|jr"|jj|jn|rkt||_|jj|j|j|j|jj |_ nOtt |j|j|j|_t j drtdn|jj|_ |jj|j|jdS(s- Process the parsed command. tLSM_DEBUG_PLUGINs8Attach debugger to plug-in, press when ready...N(RRRR R4tplugin_registerRRR tplugin_unregisterR RRRtinputtcloseR1(RR6((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyR#s $ c Csg}itjd6tjd6tjd6tjd6tjd6tjd6tjd6}x%tjD]}idd6t j d6t j d6dd6t j d6t j d6t jd6}x|jD]v}y|||||  p                  2                    /  *     (RRR(RRRR(lRR%RRsRR?R=targparseRRRtsixtlsmRRRRRRR R R R R RRRRRRRtlsm.lsmcli.data_displayRRRRRRRRRRRtPY3R_RPt collectionsRt ImportErrort ordereddictR!R:RGRMRORTRRXRdRqRxR\RRR2R$R`RRt list_choicestprovision_typesRntprovision_helptreplicate_typestreplicate_helpt policy_typest policy_helpRt policy_opttwrite_cache_policy_typestwrite_cache_policy_helptwrite_cache_policy_optt size_helpt sys_id_opttcopytsys_id_filter_optt pool_id_opttpool_id_filter_optt vol_id_opttvol_id_filter_optt fs_id_opttfs_id_filter_optt ag_id_opttag_id_filter_optt init_id_optt snap_id_optt export_id_opttnfs_export_id_filter_opttdisk_id_filter_opttsize_optttgt_id_filter_opttlocal_disk_path_opttVOL_CREATE_RAID_TYPES_STRtANON_UID_GID_NARRtobjectR"(((s6/usr/lib/python2.7/site-packages/lsm/lsmcli/cmdline.pyts        vF     -     *  G                                                                            _local_disk.py000064400000043474147576505410007413 0ustar00# Copyright (C) 2016 Red Hat, Inc. # (C) Copyright 2017 Hewlett Packard Enterprise Development LP # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: Gris Ge import six from lsm import LsmError, ErrorNumber from lsm._clib import (_local_disk_vpd83_search, _local_disk_vpd83_get, _local_disk_health_status_get, _local_disk_rpm_get, _local_disk_list, _local_disk_link_type_get, _local_disk_ident_led_on, _local_disk_ident_led_off, _local_disk_fault_led_on, _local_disk_fault_led_off, _local_disk_serial_num_get, _local_disk_led_status_get, _local_disk_link_speed_get) def _use_c_lib_function(func_ref, arg): (data, err_no, err_msg) = func_ref(arg) if err_no != ErrorNumber.OK: raise LsmError(err_no, err_msg) return data class LocalDisk(object): @staticmethod def vpd83_search(vpd83): """ lsm.LocalDisk.vpd83_search(vpd83) Version: 1.3 Usage: Find out the disk paths for given SCSI VPD page 0x83 NAA type ID. Considering multipath, certain VPD83 might have multiple disks associated. Parameters: vpd83 (string) The VPD83 NAA type ID. Returns: [disk_path] List of string. Empty list if not disk found. The disk_path string format is '/dev/sd[a-z]+' for SCSI and ATA disks. SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_vpd83_search, vpd83) @staticmethod def serial_num_get(disk_path): """ lsm.LocalDisk.serial_num_get(disk_path) Version: 1.4 Usage: Query the SCSI VPD80 serial number of given disk path. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: serial_num (string) String of VPD80 serial number. Empty string if not supported. The string format regex is: SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb' ErrorNumber.NOT_FOUND_DISK Provided disk is not found. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_serial_num_get, disk_path) @staticmethod def vpd83_get(disk_path): """ lsm.LocalDisk.vpd83_get(disk_path) Version: 1.3 Usage: Query the SCSI VPD83 NAA ID of given disk path. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: vpd83 (string) String of VPD83 NAA ID. Empty string if not supported. The string format regex is: (?:^6[0-9a-f]{31})|(?:^[235][0-9a-f]{15})$ SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb' ErrorNumber.NOT_FOUND_DISK Provided disk is not found. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_vpd83_get, disk_path) @staticmethod def health_status_get(disk_path): """ lsm.LocalDisk.health_status_get(disk_path) Version: 1.5 Usage: Retrieve the health status of given disk path. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: health_status (integer) Disk health status: -1 (lsm.Disk.HEALTH_STATUS_UNKNOWN): Unknown health status 0 (lsm.Disk.HEALTH_STATUS_FAIL): health status indicates failure 1 (lsm.Disk.HEALTH_STATUS_WARN): health status warns of near failure 2 (lsm.Disk.HEALTH_STATUS_GOOD): health status indicates good health SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb' ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Not supported. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_health_status_get, disk_path) @staticmethod def rpm_get(disk_path): """ Version: 1.3 Usage: Query the disk rotation speed - revolutions per minute (RPM) of given disk path. Require permission to open disk path as read-only and non-block, normally it's root or disk group privilege. Parameters: disk_path (string) The disk path, example '/dev/sdb', '/dev/nvme0n1'. Returns: rpm (integer) Disk rotation speed: -1 (lsm.Disk.RPM_UNKNOWN): Unknown RPM 0 (lsm.Disk.RPM_NON_ROTATING_MEDIUM): Non-rotating medium (e.g., SSD) 1 (lsm.Disk.RPM_ROTATING_UNKNOWN_SPEED): Rotational disk with unknown speed >1: Normal rotational disk (e.g., HDD) SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Not supported. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_rpm_get, disk_path) @staticmethod def list(): """ Version: 1.3 Usage: Query local disk paths. Currently, only SCSI, ATA and NVMe disks will be included. Parameters: N/A Returns: [disk_path] List of string. Empty list if not disk found. The disk_path string format is '/dev/sd[a-z]+' for SCSI and ATA disks, '/dev/nvme[0-9]+n[0-9]+' for NVMe disks. SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. Capability: N/A No capability required as this is a library level method. """ (disk_paths, err_no, err_msg) = _local_disk_list() if err_no != ErrorNumber.OK: raise LsmError(err_no, err_msg) return disk_paths @staticmethod def link_type_get(disk_path): """ Version: 1.3 Usage: Query the disk link type of given disk path. For SATA disks connected to SAS enclosure, will return lsm.Disk.LINK_TYPE_ATA. Require permission to open disk_path(root user or disk group). Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: link_type (integer) Link type, possible values are: lsm.Disk.LINK_TYPE_UNKNOWN Failed to detect link type lsm.Disk.LINK_TYPE_FC Fibre Channel lsm.Disk.LINK_TYPE_SSA Serial Storage Architecture, Old IBM tech. lsm.Disk.LINK_TYPE_SBP Serial Bus Protocol, used by IEEE 1394. lsm.Disk.LINK_TYPE_SRP SCSI RDMA Protocol lsm.Disk.LINK_TYPE_ISCSI Internet Small Computer System Interface lsm.Disk.LINK_TYPE_SAS Serial Attached SCSI lsm.Disk.LINK_TYPE_ADT Automation/Drive Interface Transport Protocol, often used by Tape. lsm.Disk.LINK_TYPE_ATA PATA/IDE or SATA. lsm.Disk.LINK_TYPE_USB USB disk. lsm.Disk.LINK_TYPE_SOP SCSI over PCI-E lsm.Disk.LINK_TYPE_PCIE PCI-E, e.g. NVMe SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED Insufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_link_type_get, disk_path) @staticmethod def ident_led_on(disk_path): """ Version: 1.3 Usage: Turn on the identification LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_ident_led_on, disk_path) @staticmethod def ident_led_off(disk_path): """ Version: 1.3 Usage: Turn off the identification LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_ident_led_off, disk_path) @staticmethod def fault_led_on(disk_path): """ Version: 1.3 Usage: Turn on the fault LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_fault_led_on, disk_path) @staticmethod def fault_led_off(disk_path): """ Version: 1.3 Usage: Turn off the fault LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_fault_led_off, disk_path) @staticmethod def led_status_get(disk_path): """ Version: 1.3 Usage: Get LED status for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: led_status (integer, bit map) Could be combination of these values: lsm.Disk.LED_STATUS_UNKNOWN lsm.Disk.LED_STATUS_IDENT_ON lsm.Disk.LED_STATUS_IDENT_OFF lsm.Disk.LED_STATUS_IDENT_UNKNOWN Has identification LED, but status is unknown. If certain disk has no identification LED, 'led_status' should not contain 'lsm.Disk.LED_STATUS_IDENT_ON' or 'lsm.Disk.LED_STATUS_IDENT_OFF' or 'lsm.Disk.LED_STATUS_IDENT_UNKNOWN' lsm.Disk.LED_STATUS_FAULT_ON lsm.Disk.LED_STATUS_FAULT_OFF lsm.Disk.LED_STATUS_FAULT_UNKNOWN Has fault LED, but status is unknown. If certain disk has no fault LED, 'led_status' should not contain 'lsm.Disk.LED_STATUS_FAULT_ON' or 'lsm.Disk.LED_STATUS_FAULT_OFF' or 'lsm.Disk.LED_STATUS_FAULT_UNKNOWN' SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_led_status_get, disk_path) @staticmethod def link_speed_get(disk_path): """ Version: 1.4 Usage: Get current negotiated logical link speed for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: link_speed Integer for link speed in Mbps. For example, '3.0 Gbps' will get 3000. SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk is not supported yet. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. """ return _use_c_lib_function(_local_disk_link_speed_get, disk_path) _pluginrunner.pyo000064400000010103147576505410010175 0ustar00 -P`c@sddlZddlZddlZddlmZmZmZddlmZddl Z ddl Z ddl m Z ddlmZdZdefdYZdS( iN(tLsmErrorterrort ErrorNumber(tcmd_line_wrapper(t SocketEOF(t TransPortcs-dkr|Stfd|DS(s{ This method does not check whether lsm_obj contain requested property. The method caller should do the check. c3s*|] }t|kr|VqdS(N(tgetattr(t.0tlsm_obj(t search_keyt search_value(s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pys #sN(tNonetlist(tlsm_objsR R ((R R s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pytsearch_propertys t PluginRunnercBs/eZdZedZdZdZRS(s] Plug-in side common code which uses the passed in plugin to do meaningful work. cCs+yt|tSWntk r&tSXdS(s4 Returns True if val is an integer. N(tinttTruet ValueErrortFalse(tval((s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pyt _is_number-s   cCst|_t|dkrtj|dryt|d}ttj|tj tj |_ y||_ WnNt k r}tj}|j jdddt|tj|nXWqt k rttjtdtjdqXnt|_t|dS(NiiiisError instantiating plug-in sPlug-in exiting.(RtcmdlinetlenRRRRtsockettfromfdtAF_UNIXt SOCK_STREAMttptplugint Exceptiontsystexc_infot send_errortstrtsixtreraiseRt tracebackt format_exctexitRR(tselfRtargstfdtetec_info((s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pyt__init__8s& %!    c Cs|jr dSt}d}z|yxtry|jj}|d}|d}|d}t|j|r|dkrt|j|}qt|j||d}nt t j d|jj ||dkrt}n|dkrt}|jj PnWq"tk rI}ttj|jj|dt|q"tk r}ttj|jj|d t|q"t k r} |jj|| j| j| jq"Xq"WWntk r|rtd qntjk r/} | jtjkrtd qtd tjnetk rtd tjy,|jj|t jd ttjWqtk rqXnXWd|r|jjtj d nXdS(NitmethodtidtparamssUnsupported operationtplugin_registertplugin_unregisteriDis!Client went away, exiting plug-ins Unhandled exception in plug-in! sUnhandled exception in plug-ini(!RRRRtread_reqthasattrRR RRRt NO_SUPPORTt send_resptcloseRRR%R&R!R"tAttributeErrortcodetmsgtdatat _SocketEOFRterrnotEPIPERt PLUGIN_BUGR2RR'( R(t need_shutdowntmsg_idR:R.R0tresulttvetaetlsm_errtse((s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pytrunTsl                  (t__name__t __module__t__doc__t staticmethodRR-RG(((s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pyR's (RR%RtlsmRRRt lsm.lsmcliRR#R=t lsm._commonRR<tlsm._transportRRtobjectR(((s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pyts      _pluginrunner.pyc000064400000010103147576505410010161 0ustar00 -P`c@sddlZddlZddlZddlmZmZmZddlmZddl Z ddl Z ddl m Z ddlmZdZdefdYZdS( iN(tLsmErrorterrort ErrorNumber(tcmd_line_wrapper(t SocketEOF(t TransPortcs-dkr|Stfd|DS(s{ This method does not check whether lsm_obj contain requested property. The method caller should do the check. c3s*|] }t|kr|VqdS(N(tgetattr(t.0tlsm_obj(t search_keyt search_value(s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pys #sN(tNonetlist(tlsm_objsR R ((R R s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pytsearch_propertys t PluginRunnercBs/eZdZedZdZdZRS(s] Plug-in side common code which uses the passed in plugin to do meaningful work. cCs+yt|tSWntk r&tSXdS(s4 Returns True if val is an integer. N(tinttTruet ValueErrortFalse(tval((s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pyt _is_number-s   cCst|_t|dkrtj|dryt|d}ttj|tj tj |_ y||_ WnNt k r}tj}|j jdddt|tj|nXWqt k rttjtdtjdqXnt|_t|dS(NiiiisError instantiating plug-in sPlug-in exiting.(RtcmdlinetlenRRRRtsockettfromfdtAF_UNIXt SOCK_STREAMttptplugint Exceptiontsystexc_infot send_errortstrtsixtreraiseRt tracebackt format_exctexitRR(tselfRtargstfdtetec_info((s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pyt__init__8s& %!    c Cs|jr dSt}d}z|yxtry|jj}|d}|d}|d}t|j|r|dkrt|j|}qt|j||d}nt t j d|jj ||dkrt}n|dkrt}|jj PnWq"tk rI}ttj|jj|dt|q"tk r}ttj|jj|d t|q"t k r} |jj|| j| j| jq"Xq"WWntk r|rtd qntjk r/} | jtjkrtd qtd tjnetk rtd tjy,|jj|t jd ttjWqtk rqXnXWd|r|jjtj d nXdS(NitmethodtidtparamssUnsupported operationtplugin_registertplugin_unregisteriDis!Client went away, exiting plug-ins Unhandled exception in plug-in! sUnhandled exception in plug-ini(!RRRRtread_reqthasattrRR RRRt NO_SUPPORTt send_resptcloseRRR%R&R!R"tAttributeErrortcodetmsgtdatat _SocketEOFRterrnotEPIPERt PLUGIN_BUGR2RR'( R(t need_shutdowntmsg_idR:R.R0tresulttvetaetlsm_errtse((s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pytrunTsl                  (t__name__t __module__t__doc__t staticmethodRR-RG(((s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pyR's (RR%RtlsmRRRt lsm.lsmcliRR#R=t lsm._commonRR<tlsm._transportRRtobjectR(((s5/usr/lib/python2.7/site-packages/lsm/_pluginrunner.pyts      version.pyo000064400000000242147576505410006776 0ustar00 -P`c@s dZdS(s1.8.1N(tVERSION(((s//usr/lib/python2.7/site-packages/lsm/version.pyts_client.pyc000064400000167523147576505410006732 0ustar00 -P`c@sddlZddlZddlmZmZmZmZmZmZm Z m Z m Z m Z m Z mZmZmZmZddlmZddlmZddlmZddlmZddlZdZdZd Z d efd YZ!dS( iN(tVolumet NfsExportt CapabilitiestPooltSystemtBatterytDiskt AccessGroupt FileSystemt FsSnapshott uri_parsetLsmErrort ErrorNumbertINetworkAttachedStoraget TargetPort(treturn_requires(tUDS_PATH(t TransPort(tIDatacCs |d=|S(s Used to remove the self key from the dict d. Self is included when calling the function locals() in a class method. tself((td((s//usr/lib/python2.7/site-packages/lsm/_client.pyt _del_self"scCs/|r+||kr+ttjd|ndS(NsUnsupported search_key: '%s'(R R tUNSUPPORTED_SEARCH_KEY(t search_keytsupported_keys((s//usr/lib/python2.7/site-packages/lsm/_client.pyt_check_search_key+s cCsttjddS(Ns`The libStorageMgmt daemon is not running (process name lsmd), try 'service libstoragemgmt start'(R R tDAEMON_NOT_RUNNING(((s//usr/lib/python2.7/site-packages/lsm/_client.pyt_raise_no_daemon3s tClientcBseZdZdIZdJZdKZdLZddZddZe dZ e dZ dMddd Z edMed ZedMed Ze eejdgd ed ZedMedZeeedZeeeeedZedMedZeeedZeejdejdedZeegdMdMedZeegedZ edMedZ!edMedZ"ee#gdMdMedZ$eejde#edZ%eejde#edZ&eejde#edZ'eeedZ(eejdedZ)eejdedZ*edMedZ+edMed Z,ee-gdMdMed!Z.edMed"Z/edMed#Z0ee1gdMdMed$Z2ee1ed%Z3edMed&Z4ee1ed'Z5ee1ed(Z6ee#ged)Z7ee1ged*Z8ee9ed+Z:eejded,Z;ee<gdMdMed-Z=eejded.Z>eejde<ed/Z?eejde<ed0Z@eejde<dMed1ZAeejddMed2ZBeeCged3ZDeejdeCed4ZEeejded5ZFeejdeGed6ZHee9ed7ZIeejded8ZJeejdged9ZKeeLgdMdMed:ZMeeLeLjNeLjNdMdMed;ZOedMed<ZPeeQgdMdMed=ZReeeeeeged>ZSeeeejdgged?ZTeegegged@ZUee#edAZVedMedBZWedMedCZXeeYgdMdMedDZZeeeeeegedEZ[edMedFZ\edMedGZ]edMedHZ^RS(NiiiicCstddS(NsDo not call directly!(t RuntimeError(Rturitplain_text_passwordt timeout_mstflags((s//usr/lib/python2.7/site-packages/lsm/_client.pytplugin_registerQscCs |jjdttdS(s3 Instruct the plug-in to get ready R"N(t_tptrpcRtlocals(RRtpasswordttimeoutR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyt__start[scCstj}tjj|rx~tj|D]j\}}}xX|D]P}tjj||}y!tj|}|j t SWqDt k rqDXqDWq.Wnt S(N( Rt_plugin_uds_pathtostpathtexiststwalktjoint _TransPortt get_sockettclosetTrueR tFalse(tuds_pathtroott sub_folderstfilestfilenametudsts((s//usr/lib/python2.7/site-packages/lsm/_client.pyt_check_daemon_existses    cCs)t}dtjkr%tjd}n|S(Nt LSM_UDS_PATH(t _UDS_PATHR*tenviron(trc((s//usr/lib/python2.7/site-packages/lsm/_client.pyR)ysi0uc Cs||_||_||_tj|_t|dg}|d}d|krp|jd\}}|}ntj j |j||_ tj j |j rt t j|j |_n/tjrttjd|j nt|j||||dS(Ntschemet+sPlug-in %s not found!(t_urit _passwordt_timeoutRR)t _uds_pathR tsplitR*R+R.t plugin_pathR,R/R0R#R;R R tPLUGIN_NOT_EXISTRt_Client__start( RRRR R!tuR@tplugtproto((s//usr/lib/python2.7/site-packages/lsm/_client.pyt__init__s"        cCs|j|dS(s$ Synonym for close. N(R1(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pytplugin_unregisterscCs6|jjdtt|jjd|_dS(sB Does an orderly plugin_unregister of the plug-in RNN(R#R$RR%R1tNone(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR1s t:c Csg}tjstntj}xtj|D]\}}}x}|D]u}tjj||}ttj |} | j dt d|\} } |j d| || f| j qNWq8W|S(s Retrieves all the available plug-ins Return list of strings of available plug-ins with the "descversion" t plugin_infoR!s%s%s%s(RR;RR)R*R-R+R.R/R0R$tdicttappendR1( t field_sepR!R?R4R5R6R7R8R9ttptitv((s//usr/lib/python2.7/site-packages/lsm/_client.pytavailable_pluginss     !cCs|jjdttS(sr Sets any time-outs for the plug-in (ms) Return None on success, else LsmError exception t time_out_set(R#R$RR%(RtmsR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRYscCs|jjdttS(sd Retrieves the current time-out Return time-out in ms, else raise LsmError t time_out_get(R#R$RR%(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR[scCs|jjdttS(s Returns the stats of the given job. Returns a tuple ( status (enumeration), percent_complete, completed item). else LsmError exception. t job_status(R#R$RR%(Rtjob_idR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR\s cCs|jjdttS(ss Frees resources for a given job number. Returns None on success, else raises an LsmError tjob_free(R#R$RR%(RR]R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR^scCs|jjdttS(sv Fetches the capabilities of the array Returns a capability object, see data,py for details. t capabilities(R#R$RR%(RtsystemR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR_scCs|jjdttS(s> Returns a description and version of plug-in RQ(R#R$RR%(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRQ"scCs,t|tj|jjdttS(s Returns an array of pool objects. Pools are used in both block and file system interfaces, thus the reason they are in the base class. tpools(RRtSUPPORTED_SEARCH_KEYSR#R$RR%(RRt search_valueR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRa/scCs|jjdttS(s Returns an array of system objects. System information is used to distinguish resources from on storage array to another when the plug=in supports the ability to have more than one array managed by it tsystems(R#R$RR%(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRd<scCstjddkr@t|ttfsdttjdqdn$t|tsdttjdn|dks||dkrttjdn|jj dt t S(s lsm.Client.system_read_cache_pct_update(self, system, read_pct, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: This method updates the read cache percentage on a system if supported Parameters: system(lsm.System) an lsm.System object. read_pct(int) the desired read cache percentage. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: returns None on success, else raises LsmError on errors. SpecialExceptions: iis&Invalid read_pct, should be an integerids,Invalid read_pct, should be in range 0 - 100tsystem_read_cache_pct_update( tsyst version_infot isinstancetinttlongR R tINVALID_ARGUMENTR#R$RR%(RR`tread_pctR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyReKs      cCs5tj|tjdt|jjdttS(sg Register a user/password for the specified initiator for CHAP authentication. traise_exceptiontiscsi_chap_auth(Rtinitiator_id_verifytINIT_TYPE_ISCSI_IQNR2R#R$RR%(Rtinit_idtin_usert in_passwordtout_usert out_passwordR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRn}s  cCs,t|tj|jjdttS(s4 Returns an array of volume objects tvolumes(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRvscCs|jjdttS(s Creates a volume, given a pool, volume name, size and provisioning returns a tuple (job_id, new volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. t volume_create(R#R$RR%(Rtpoolt volume_namet size_bytest provisioningR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRws cCs|jjdttS(s Re-sizes a volume. Returns a tuple (job_id, re-sized_volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. t volume_resize(R#R$RR%(Rtvolumetnew_size_bytesR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR|s cCs|jjdttS(s Replicates a volume from the specified pool. Returns a tuple (job_id, replicated volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. tvolume_replicate(R#R$RR%(RRxtrep_typet volume_srctnameR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(sB Returns the size of a replicated block in bytes. t!volume_replicate_range_block_size(R#R$RR%(RR`R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(s- Replicates a portion of a volume to itself or another volume. The src, dest and number of blocks values change with vendor, call volume_replicate_range_block_size to get block unit size. Returns Job id or None when completed, else raises LsmError on errors. tvolume_replicate_range(R#R$RR%(RRRt volume_desttrangesR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(sQ Deletes a volume. Returns None on success, else job id t volume_delete(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(sx Makes a volume available to the host returns None on success, else raises LsmError on errors. t volume_enable(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR scCs|jjdttS(sz Makes a volume unavailable to the host returns None on success, else raises LsmError on errors. tvolume_disable(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs,t|tj|jjdttS(s2 Returns an array of disk objects tdisks(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR*scCs|jjdttS(s< Allows an access group to access a volume. t volume_mask(R#R$RR%(Rt access_groupR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR8scCs|jjdttS(sA Revokes access for an access group for a volume t volume_unmask(R#R$RR%(RRR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyREscCs,t|tj|jjdttS(s1 Returns a list of access groups t access_groups(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRRscCs>tj||dtd\}}|jjdttS(ss Creates an access group and add the specified initiator id, init_type and desired access. Rmitaccess_group_create(RRoR2R#R$RR%(RRRqt init_typeR`R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRcscCs|jjdttS(s) Deletes an access group taccess_group_delete(R#R$RR%(RRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRsscCs>tj||dtd\}}|jjdttS(s6 Adds an initiator to an access group Rmitaccess_group_initiator_add(RRoR2R#R$RR%(RRRqRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs8tj|ddtd}|jjdttS(s; Deletes an initiator from an access group Rmitaccess_group_initiator_deleteN(RRoROR2R#R$RR%(RRRqRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs  cCs|jjdttS(sN Returns the list of volumes that access group has access to. t"volumes_accessible_by_access_group(R#R$RR%(RRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(se Returns the list of access groups that have access to the specified volume. taccess_groups_granted_to_volume(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(s Returns True if this volume has other volumes which are dependant on it. Implies that this volume cannot be deleted or possibly modified because it would affect its children. tvolume_child_dependency(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(s If this volume has child dependency, this method call will fully replicate the blocks removing the relationship between them. This should return None (success) if volume_child_dependency would return False. Note: This operation could take a very long time depending on the size of the volume and the number of child dependencies. Returns None if complete else job id, raises LsmError on errors. tvolume_child_dependency_rm(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs,t|tj|jjdttS(sC Returns a list of file systems on the controller. tfs(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(s WARNING: Destructive Deletes a file system and everything it contains Returns None on success, else job id t fs_delete(R#R$RR%(RRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(s Re-size a file system Returns a tuple (job_id, re-sized file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. t fs_resize(R#R$RR%(RRR~R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(s  Creates a file system given a pool, name and size. Note: size is limited to 2**64 bytes Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. t fs_create(R#R$RR%(RRxRRzR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(s# Creates a thin, point in time read/writable copy of src to dest. Optionally uses snapshot as backing of src_fs Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. tfs_clone(R#R$RR%(Rtsrc_fst dest_fs_nametsnapshotR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR&s cCs|jjdttS(s Creates a thinly provisioned clone of src to dest. Note: Source and Destination are required to be on same filesystem and all directories in destination path need to exist. Returns None on success, else job id t fs_file_clone(R#R$RR%(RRt src_file_nametdest_file_nameRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR;s cCs|jjdttS(sO Returns a list of snapshot names for the supplied file system t fs_snapshots(R#R$RR%(RRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRLscCs|jjdttS(s| Snapshot is a point in time read-only copy Create a snapshot on the chosen file system. Returns a tuple (job_id, snapshot) Notes: - Snapshot name may not match what was passed in (depends on array implementation) - Tuple return values are mutually exclusive, when one is None the other must be valid. tfs_snapshot_create(R#R$RR%(RRt snapshot_nameR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRYscCs|jjdttS(s Frees the re-sources for the given snapshot on the supplied filesystem. Returns None on success else job id, LsmError exception on error tfs_snapshot_delete(R#R$RR%(RRRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRoscCs|jjdttS(s6 WARNING: Destructive! Reverts a file-system or just the specified files from the snapshot. If a list of files is supplied but the array cannot restore just them then the operation will fail with an LsmError raised. If files == None and all_files = True then all files on the file-system are restored. Restore_file if None none must be the same length as files with each index in each list referring to the associated file. Returns None on success, else job id, LsmError exception on error tfs_snapshot_restore(R#R$RR%(RRRR7t restore_filest all_filesR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(s& Returns True if the specified filesystem or specified file on this file system has child dependencies. This implies that this filesystem or specified file on this file system cannot be deleted or possibly modified because it would affect its children. tfs_child_dependency(R#R$RR%(RRR7R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(s If this filesystem or specified file on this filesystem has child dependency this method will fully replicate the blocks removing the relationship between them. This should return None(success) if fs_child_dependency would return False. Note: This operation could take a very long time depending on the size of the filesystem and the number of child dependencies. Returns None if completed, else job id. Raises LsmError on errors. tfs_child_dependency_rm(R#R$RR%(RRR7R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(sH What types of NFS client authentication are supported. t export_auth(R#R$RR%(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs,t|tj|jjdttS(sL Get a list of all exported file systems on the controller. texports(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRsc CsQt|t|t|r5ttjdn|jjdttS(sD Exports a filesystem as specified in the arguments s(Host cannot both in rw_list and ro_list.t export_fs(tsetR R RkR#R$RR%( Rtfs_idt export_patht root_listtrw_listtro_listtanon_uidtanon_gidt auth_typetoptionsR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs   cCs|jjdttS(s. Removes the specified export t export_remove(R#R$RR%(RtexportR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs,t|tj|jjdttS(s0 Returns a list of target ports t target_ports(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(sQuery the RAID information of certain volume. New in version 1.2. Query the RAID type, strip size, extents count, minimum I/O size, optimal I/O size of given volume. This method requires this capability: lsm.Capabilities.VOLUME_RAID_INFO Args: volume (Volume object): Volume to query flags (int): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: [raid_type, strip_size, disk_count, min_io_size, opt_io_size] raid_type (int): RAID Type of requested volume. Could be one of these values: Volume.RAID_TYPE_RAID0 Stripe Volume.RAID_TYPE_RAID1 Two disks Mirror Volume.RAID_TYPE_RAID3 Byte-level striping with dedicated parity Volume.RAID_TYPE_RAID4 Block-level striping with dedicated parity Volume.RAID_TYPE_RAID5 Block-level striping with distributed parity Volume.RAID_TYPE_RAID6 Block-level striping with two distributed parities, aka, RAID-DP Volume.RAID_TYPE_RAID10 Stripe of mirrors Volume.RAID_TYPE_RAID15 Parity of mirrors Volume.RAID_TYPE_RAID16 Dual parity of mirrors Volume.RAID_TYPE_RAID50 Stripe of parities Volume.RAID_TYPE_RAID60 Stripe of dual parities Volume.RAID_TYPE_RAID51 Mirror of parities Volume.RAID_TYPE_RAID61 Mirror of dual parities Volume.RAID_TYPE_JBOD Just bunch of disks, no parity, no striping. Volume.RAID_TYPE_UNKNOWN The plugin failed to detect the volume's RAID type. Volume.RAID_TYPE_MIXED This volume contains multiple RAID settings. Volume.RAID_TYPE_OTHER Vendor specific RAID type strip_size(int): The size of strip on each disk or other storage extent. For RAID1/JBOD, it should be set as sector size. If plugin failed to detect strip size, it should be set as Volume.STRIP_SIZE_UNKNOWN(0). disk_count(int): The count of disks used for assembling the RAID group(s) where this volume allocated from. For any RAID system using the slice of disk, this value indicate how many disk slices are used for the RAID. For example, on LVM RAID, the 'disk_count' here indicate the count of PVs used for certain volume. Another example, on EMC VMAX, the 'disk_count' here indicate how many hyper volumes are used for this volume. For any RAID system using remote LUN for data storing, each remote LUN should be count as a disk. If the plugin failed to detect disk_count, it should be set as Volume.DISK_COUNT_UNKNOWN(0). min_io_size(int): The minimum I/O size, device preferred I/O size for random I/O. Any I/O size not equal to a multiple of this value may get significant speed penalty. Normally it refers to strip size of each disk(extent). If plugin failed to detect min_io_size, it should try these values in the sequence of: logical sector size -> physical sector size -> Volume.MIN_IO_SIZE_UNKNOWN(0). opt_io_size(int): The optimal I/O size, device preferred I/O size for sequential I/O. Normally it refers to RAID group stripe size. If plugin failed to detect opt_io_size, it should be set to Volume.OPT_IO_SIZE_UNKNOWN(0). Raises: LsmError: ErrorNumber.NO_SUPPORT No support. tvolume_raid_info(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR s[cCs|jjdttS(s? lsm.Client.pool_member_info(self, pool, flags=lsm.Client.FLAG_RSVD) Version: 1.2 Usage: Query the membership information of certain pool: RAID type, member type and member ids. Currently, LibStorageMgmt supports two types of pool: * Sub-pool -- Pool.MEMBER_TYPE_POOL Pool space is allocated from parent pool. Example: * NetApp ONTAP volume * Disk RAID pool -- Pool.MEMBER_TYPE_DISK Pool is a RAID group assembled by disks. Example: * LSI MegaRAID disk group * EMC VNX pool * NetApp ONTAP aggregate Parameters: pool (lsm.Pool object) Pool to query flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: [raid_type, member_type, member_ids] raid_type (int) RAID Type of requested pool. Could be one of these values: Volume.RAID_TYPE_RAID0 Stripe Volume.RAID_TYPE_RAID1 Two disks Mirror Volume.RAID_TYPE_RAID3 Byte-level striping with dedicated parity Volume.RAID_TYPE_RAID4 Block-level striping with dedicated parity Volume.RAID_TYPE_RAID5 Block-level striping with distributed parity Volume.RAID_TYPE_RAID6 Block-level striping with two distributed parities, aka, RAID-DP Volume.RAID_TYPE_RAID10 Stripe of mirrors Volume.RAID_TYPE_RAID15 Parity of mirrors Volume.RAID_TYPE_RAID16 Dual parity of mirrors Volume.RAID_TYPE_RAID50 Stripe of parities Volume.RAID_TYPE_RAID60 Stripe of dual parities Volume.RAID_TYPE_RAID51 Mirror of parities Volume.RAID_TYPE_RAID61 Mirror of dual parities Volume.RAID_TYPE_JBOD Just bunch of disks, no parity, no striping. Volume.RAID_TYPE_UNKNOWN The plugin failed to detect the volume's RAID type. Volume.RAID_TYPE_MIXED This pool contains multiple RAID settings. Volume.RAID_TYPE_OTHER Vendor specific RAID type member_type (int) Could be one of these values: Pool.MEMBER_TYPE_POOL Current pool(also known as sub-pool) is allocated from other pool(parent pool). The 'raid_type' will set to RAID_TYPE_OTHER unless certain RAID system support RAID using space of parent pools. Pool.MEMBER_TYPE_DISK Pool is created from RAID group using whole disks. Pool.MEMBER_TYPE_OTHER Vendor specific RAID member type. Pool.MEMBER_TYPE_UNKNOWN Plugin failed to detect the RAID member type. member_ids (list of strings) When 'member_type' is Pool.MEMBER_TYPE_POOL, the 'member_ids' will contain a list of parent Pool IDs. When 'member_type' is Pool.MEMBER_TYPE_DISK, the 'member_ids' will contain a list of disk IDs. When 'member_type' is Pool.MEMBER_TYPE_OTHER or Pool.MEMBER_TYPE_UNKNOWN, the member_ids should be an empty list. SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_POOL Capability: lsm.Capabilities.POOL_MEMBER_INFO tpool_member_info(R#R$RR%(RRxR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRns`cCs|jjdttS(s lsm.Client.volume_raid_create_cap_get( self, system, flags=lsm.Client.FLAG_RSVD) Version: 1.2 Usage: This method is dedicated to local hardware RAID cards. Query out all supported RAID types and strip sizes which could be used by lsm.Client.volume_raid_create() method. Parameters: system (lsm.System) Instance of lsm.System flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: [raid_types, strip_sizes] raid_types ([int]) List of integer, possible values are: Volume.RAID_TYPE_RAID0 Volume.RAID_TYPE_RAID1 Volume.RAID_TYPE_RAID5 Volume.RAID_TYPE_RAID6 Volume.RAID_TYPE_RAID10 Volume.RAID_TYPE_RAID50 Volume.RAID_TYPE_RAID60 strip_sizes ([int]) List of integer. Stripe size in bytes. SpecialExceptions: LsmError lsm.ErrorNumber.NO_SUPPORT Method not supported. Sample: lsm_client = lsm.Client('sim://') lsm_sys = lsm_client.systems()[0] disks = lsm_client.disks( search_key='system_id', search_value=lsm_sys.id) free_disks = [d for d in disks if d.status == Disk.STATUS_FREE] supported_raid_types, supported_strip_sizes = lsm_client.volume_raid_create_cap_get(lsm_sys) new_vol = lsm_client.volume_raid_create( 'test_volume_raid_create', supported_raid_types[0], free_disks, supported_strip_sizes[0]) Capability: lsm.Capabilities.VOLUME_CREATE_RAID This method is mandatory when volume_raid_create() is supported. tvolume_raid_create_cap_get(R#R$RR%(RR`R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs5c Cst|dkr'ttjdn|tjkr]t|dkr]ttjdn|tjkrt|dkrttjdn|tjkrt|dkrttjdn|tjkrt|dst|dkrttjd qn|tj kr[t|dsCt|d kr[ttjd q[n|tj krt|dst|d krttjd qn|j j dt tS(s lsm.Client.volume_raid_create(self, name, raid_type, disks, strip_size, flags=lsm.Client.FLAG_RSVD) Version: 1.2 Usage: This method is dedicated to local hardware RAID cards. Create a disk RAID pool and allocate entire storage space to new volume using requested volume name. When dealing with RAID10, 50 or 60, the first half part of 'disks' will be located in one bottom layer RAID group. The new volume and new pool will created within the same system of provided disks. This method does not allow duplicate call, when duplicate call was issued, LsmError with ErrorNumber.DISK_NOT_FREE will be raise. User should check disk.status for Disk.STATUS_FREE before invoking this method. Parameters: name (string) The name for new volume. The requested volume name might be ignored due to restriction of hardware RAID vendors. The pool name will be automatically chosen by plugin. raid_type (int) The RAID type for the RAID group, possible values are: Volume.RAID_TYPE_RAID0 Volume.RAID_TYPE_RAID1 Volume.RAID_TYPE_RAID5 Volume.RAID_TYPE_RAID6 Volume.RAID_TYPE_RAID10 Volume.RAID_TYPE_RAID15 Volume.RAID_TYPE_RAID16 Volume.RAID_TYPE_RAID50 Please check volume_raid_create_cap_get() returns to get supported all raid types of current hardware RAID card. disks ([lsm.Disks,]) A list of lsm.Disk objects. Free disks used for new RAID group. strip_size (int) The size in bytes of strip. When setting strip_size to Volume.VCR_STRIP_SIZE_DEFAULT, it allow hardware RAID cards to choose their default value. Please use volume_raid_create_cap_get() method to get all supported strip size of current hardware RAID card. The Volume.VCR_STRIP_SIZE_DEFAULT is always supported when lsm.Capabilities.VOLUME_CREATE_RAID is supported. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: lsm.Volume The lsm.Volume object for newly created volume. SpecialExceptions: LsmError lsm.ErrorNumber.NO_SUPPORT Method not supported or RAID type not supported. lsm.ErrorNumber.DISK_NOT_FREE Disk is not in Disk.STATUS_FREE status. lsm.ErrorNumber.NOT_FOUND_DISK Disk not found lsm.ErrorNumber.INVALID_ARGUMENT 1. Invalid input argument data. 2. Disks are not from the same system. 3. Disks are not from the same enclosure. 4. Invalid strip_size. 5. Disk count are meet the minimum requirement: RAID1: len(disks) == 2 RAID5: len(disks) >= 3 RAID6: len(disks) >= 4 RAID10: len(disks) % 2 == 0 and len(disks) >= 4 RAID50: len(disks) % 2 == 0 and len(disks) >= 6 RAID60: len(disks) % 2 == 0 and len(disks) >= 8 lsm.ErrorNumber.NAME_CONFLICT Requested name is already be used by other volume. Sample: lsm_client = lsm.Client('sim://') disks = lsm_client.disks() free_disks = [d for d in disks if d.status == Disk.STATUS_FREE] new_vol = lsm_client.volume_raid_create( 'raid0_vol1', Volume.RAID_TYPE_RAID0, free_disks) Capability: lsm.Capabilities.VOLUME_CREATE_RAID Indicate current system support volume_raid_create() method. At least one RAID type should be supported. The strip_size == Volume.VCR_STRIP_SIZE_DEFAULT is supported. is.Illegal input disks argument: no disk includedis7Illegal input disks argument: RAID 1 only allow 2 disksis<Illegal input disks argument: RAID 5 require 3 or more disksis<Illegal input disks argument: RAID 6 require 4 or more diskssRIllegal input disks argument: RAID 10 require even disks count and 4 or more disksisRIllegal input disks argument: RAID 50 require even disks count and 6 or more disksisRIllegal input disks argument: RAID 60 require even disks count and 8 or more diskstvolume_raid_create(tlenR R RkRtRAID_TYPE_RAID1tRAID_TYPE_RAID5tRAID_TYPE_RAID6tRAID_TYPE_RAID10tRAID_TYPE_RAID50tRAID_TYPE_RAID60R#R$RR%(RRt raid_typeRt strip_sizeR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs@Y ! ! ! """cCs|jjdttS(sF lsm.Client.volume_ident_led_on(self, volume, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: This method enables the IDENT LED on a volume if supported Parameters: volume (lsm.Volume) An lsm.Volume object. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: returns None on success, else raises LsmError on errors. SpecialExceptions: tvolume_ident_led_on(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(sK lsm.Client.volume_ident_led_off(self, volume, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: This method disables the IDENT LED on a volume if supported Parameters: volume (lsm.Volume) An lsm.Volume object. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: returns None on success, else raises LsmError on errors. SpecialExceptions: tvolume_ident_led_off(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs,t|tj|jjdttS(s~ lsm.Client.batteries(self, search_key=None, search_value=None, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Query batteries. When present, super capacitors will also be included. Parameters: search_key (string, optional) The key name for the search. Valid search keys are stored in lsm.Battery.SUPPORTED_SEARCH_KEYS search_value (string, optional) The value of search_key to match. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: [lsm.Battery] lsm.Battery (object) lsm.Battery.id (string) Unique ID for this cache hardware. lsm.Battery.name (string) Human friendly name, might include physical location, model name and etc. lsm.Battery.type (int) The hardware type of cache. Could be one of these values: lsm.Battery.TYPE_CHEMICAL Chemical battery. lsm.Battery.TYPE_CAPACITOR Supper capacitor. lsm.Battery.TYPE_OTHER Vendor specific battery type. lsm.Battery.TYPE_UNKNOWN Unknown type. lsm.Battery.status (int, bitmap) Could be any combination of these values: lsm.Battery.STATUS_OK Battery is fully charged, health and not in use currently. lsm.Battery.STATUS_DISCHARGING Battery is in use. lsm.Battery.STATUS_CHARGING Battery is charging. lsm.Battery.STATUS_LEARNING Battery is calibrating itself by discharging battery and recharging again. lsm.Battery.STATUS_DEGRADED Battery is in degraded mode, need attention. For example, battery is near end of life. lsm.Battery.STATUS_ERROR Battery is having hardware error or end of life. lsm.Battery.STATUS_OTHER Vendor specific status. lsm.Battery.STATUS_UNKNOWN Unknown. lsm.Battery.system_id (string) The id of system which current battery belong to. SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT Capability: lsm.Capabilities.BATTERIES t batteries(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRsBcCs|jjdttS(s lsm.Client.volume_cache_info(self, volume, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Query RAM cache setting and status of specified volume on read and write I/O. Parameters: volume (Lsm.Volume) The lsm.Volume instance. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: [int, int, int, int, int] write_cache_policy (int) The write cache policy. Valid values are: * lsm.Volume.WRITE_CACHE_POLICY_WRITE_BACK The storage system will use write back mode if cache hardware found. * lsm.Volume.WRITE_CACHE_POLICY_AUTO The controller will use write back mode when battery/capacitor is in good health, otherwise, write through mode. * lsm.Volume.WRITE_CACHE_POLICY_WRITE_THROUGH The storage system will use write through mode. * lsm.Volume.WRITE_CACHE_POLICY_UNKNOWN Plugin failed to detect this setting. write_cache_status (int) The status of write cache. Valid values are: * lsm.Volume.WRITE_CACHE_STATUS_WRITE_THROUGH * lsm.Volume.WRITE_CACHE_STATUS_WRITE_BACK * lsm.Volume.WRITE_CACHE_STATUS_UNKNOWN read_cache_policy (int) The policy for read cache. Valid values are: * lsm.Volume.READ_CACHE_POLICY_ENABLED Read cache is enabled, when reading I/O on previous unchanged written I/O or read I/O in cache will be returned to I/O initiator immediately without checking backing store(normally disk). * lsm.Volume.READ_CACHE_POLICY_DISABLED Read cache is disabled. * lsm.Volume.READ_CACHE_POLICY_UNKNOWN Plugin failed to detect the read cache policy. read_cache_status (int) The status of read cache. Valid values are: * lsm.Volume.READ_CACHE_STATUS_ENABLED * lsm.Volume.READ_CACHE_STATUS_DISABLED * lsm.Volume.READ_CACHE_STATUS_UNKNOWN physical_disk_cache (int) Whether physical disk's cache is enabled or not. Please be advised, HDD's physical disk ram cache might be not protected by storage system's battery or capacitor on sudden power loss, you could lose data if a power failure occurs during a write process. For SSD's physical disk cache, please check with the vendor of your hardware RAID card and SSD disk. Valid values are: * lsm.Volume.PHYSICAL_DISK_CACHE_ENABLED Physical disk cache enabled. * lsm.Volume.PHYSICAL_DISK_CACHE_DISABLED Physical disk cache disabled. * lsm.Volume.PHYSICAL_DISK_CACHE_USE_DISK_SETTING Physical disk cache is determined by the disk vendor via physical disks' SCSI caching mode page(0x08 page). It is strongly suggested to change this value to lsm.Volume.PHYSICAL_DISK_CACHE_ENABLED or lsm.Volume.PHYSICAL_DISK_CACHE_DISABLED * lsm.Volume.PHYSICAL_DISK_CACHE_UNKNOWN Plugin failed to detect the physical disk status. SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_CACHE_INFO tvolume_cache_info(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRsRcCsO|tjkr3|tjkr3ttjdn|jjdtt S(s lsm.Client.volume_physical_disk_cache_update(self, volume, pdc, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Change the setting of RAM physical disk cache of specified volume. On some product(like HPE SmartArray), this action will be effective at system level which means that even you are requesting a change on a specified volume, this change will apply to all other volumes on the same controller(system). Parameters: volume (Lsm.Volume) The lsm.Volume instance. pdc (int) lsm.Volume.PHYSICAL_DISK_CACHE_ENABLED Enable physical disk cache. lsm.Volume.PHYSICAL_DISK_CACHE_DISABLED Disable physical disk cache flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: N/A SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT You might also get NO_SUPPORT error when trying to change SSD physical disk cache on MegaRAID. ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_PHYSICAL_DISK_CACHE_SET Allow changing physical disk cache. lsm.Capabilities.VOLUME_PHYSICAL_DISK_CACHE_SET_SYSTEM_LEVEL Indicate that this action will change system settings which are effective on all volumes in this storage system. For example, on HPE SmartArray, the physical disk cache setting is a controller level setting. s`Argument pdc should be Volume.PHYSICAL_DISK_CACHE_ENABLED or Volume.PHYSICAL_DISK_CACHE_DISABLEDt!volume_physical_disk_cache_update( RtPHYSICAL_DISK_CACHE_ENABLEDtPHYSICAL_DISK_CACHE_DISABLEDR R RkR#R$RR%(RR}tpdcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRhs )   cCs^|tjkrB|tjkrB|tjkrBttjdn|jjdt t S(s lsm.Client.volume_write_cache_policy_update(self, volume, wcp, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Change the RAM write cache policy on specified volume. If lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_IMPACT_READ is supported(e.g. HPE SmartArray), the changes on write cache policy might also impact read cache policy. If lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WB_IMPACT_OTHER is supported(e.g. HPE SmartArray), changing write cache policy to write back mode might impact other volumes in the same system. Parameters: volume (Lsm.Volume) The lsm.Volume instance. wcp (int) Could be one of these value: * lsm.Volume.WRITE_CACHE_POLICY_WRITE_BACK Change to write back mode. * lsm.Volume.WRITE_CACHE_POLICY_AUTO Change to auto mode: use write back mode when battery/capacitor is healthy, otherwise use write through. * lsm.Volume.WRITE_CACHE_POLICY_WRITE_THROUGH Change to write through mode. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: N/A SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WRITE_BACK Allow changing to always mode. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_AUTO Allow changing to auto mode. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WRITE_THROUGH Allow changing to disable mode. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_IMPACT_READ Indicate this action might impact read cache policy. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WB_IMPACT_OTHER Indicate that changing to write back mode might impact other volumes. For example, on HPE SmartArray, changing to write back mode will change all other volumes with auto write cache policy to write back mode. sArgument wcp should be Volume.WRITE_CACHE_POLICY_WRITE_BACK or Volume.WRITE_CACHE_POLICY_AUTO or Volume.WRITE_CACHE_POLICY_WRITE_THROUGHt volume_write_cache_policy_update( RtWRITE_CACHE_POLICY_WRITE_BACKtWRITE_CACHE_POLICY_AUTOt WRITE_CACHE_POLICY_WRITE_THROUGHR R RkR#R$RR%(RR}twcpR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs4   cCsO|tjkr3|tjkr3ttjdn|jjdtt S(s lsm.Client.volume_read_cache_policy_update(self, volume, rcp, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Change the RAM read cache policy of specified volume. If lsm.Capabilities.VOLUME_READ_CACHE_POLICY_SET_IMPACT_WRITE is supported(like HPE SmartArray), the change on write cache policy might also impact read cache policy. Parameters: volume (Lsm.Volume) The lsm.Volume instance. rcp (int) Could be one of these value: * lsm.Volume.READ_CACHE_POLICY_ENABLED Enable read cache. * lsm.Volume.READ_CACHE_POLICY_DISABLED Disable read cache. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: N/A SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_READ_CACHE_POLICY_SET Allow enabling or disabling read cache policy. lsm.Capabilities.VOLUME_READ_CACHE_POLICY_SET_IMPACT_WRITE Indicate that changing read cache policy might impact write cache policy. For example, on HPE SmartArray, disabling read cache will also change write cache policy to write through. s\Argument rcp should be Volume.READ_CACHE_POLICY_ENABLED or Volume.READ_CACHE_POLICY_DISABLEDtvolume_read_cache_policy_update( RtREAD_CACHE_POLICY_ENABLEDtREAD_CACHE_POLICY_DISABLEDR R RkR#R$RR%(RR}trcpR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs &   iiiiN(_t__name__t __module__t FLAG_RSVDt#FLAG_VOLUME_CREATE_USE_SYSTEM_CACHEt%FLAG_VOLUME_CREATE_USE_IO_PASSTHROUGHt'FLAG_VOLUME_CREATE_DISABLE_SYSTEM_CACHEt)FLAG_VOLUME_CREATE_DISABLE_IO_PASSTHROUGHR"RIt staticmethodR;R)RORMt_return_requiresRNR1tsixt string_typesRXRYRiR[t_IDataR\R^RR_RQRRaRRdReRnRRvRwR|RRRRRRRRRRRRRRRRRRtboolRRRRRRRRRR RRRR3RRRRRRtANON_UID_GID_NARRRRRRRRRRRRRRRR(((s//usr/lib/python2.7/site-packages/lsm/_client.pyR@s             1                           ag>    DS 2 > ("R*RftlsmRRRRRRRRRR R R R R Rt lsm._commonRRRR=tlsm._transportRR/t lsm._dataRRRRRRR(((s//usr/lib/python2.7/site-packages/lsm/_client.pyts  d   _iplugin.pyo000064400000052122147576505410007123 0ustar00 -P`c@sddlmZddlmZddlmZmZddlm Z de ee fdYZ de fdYZ d e fd YZ d e fd YZd S(i(tABCMeta(tabstractmethod(tLsmErrort ErrorNumber(twith_metaclasstIPlugincBseZdZeddZeddZeddZeddZeddZeddZ eddZ edd Z ed d dd Z edd ZRS( sU Plug-in interface that all plug-ins must implement for basic operation. icCsdS(s Method first called to setup the plug-in (except for plugin_info) This would be the place to make a connection to the array. Returns None on success, else LsmError exception N((tselfturitpasswordttimeouttflags((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytplugin_registers cCsdS(ss Sets any time-outs for the plug-in (ms) Returns None on success, else LsmError exception N((RtmsR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt time_out_set(scCsdS(se Retrieves the current time-out Returns time-out in ms, else raise LsmError N((RR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt time_out_get1scCsdS(sZ Called when the client wants to finish up or the socket goes eof. Plug-in should clean up all resources. Note: In the case where the socket goes EOF and the plugin_unregister runs into errors the exception(s) will not be delivered to the client! Returns None on success, else LsmError exception N((RR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytplugin_unregister:s cCsdS(s Returns the stats of the given job. Returns a tuple ( status (enumeration), percent_complete, completed item). else LsmError exception. N((Rtjob_idR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt job_statusFs cCsdS(sl Frees resources for a given job. Returns None on success, else raises an LsmError N((RRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytjob_freeQscCsdS(sS Returns the capabilities for the selected system, raises LsmError N((RtsystemR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt capabilitiesZscCsdS(s Returns the description and version for plug-in, raises LsmError Note: Make sure plugin can handle this call before plugin_register is called. N((RR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt plugin_infoascCsdS(s Returns an array of pool objects. Pools are used in both block and file system interfaces, thus the reason they are in the base class. Raises LsmError on error N((Rt search_keyt search_valueR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytpoolskscCsdS(s  Returns an array of system objects. System information is used to distinguish resources from on storage array to another when the plug=in supports the ability to have more than one array managed by it Raises LsmError on error N((RR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytsystemsus N(t__name__t __module__t__doc__t_abstractmethodR R RRRRRRtNoneRR(((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyRs*     tIStorageAreaNetworkcBseZddddZddZddZddZddZddZddZ ddZ dd Z d Z dd Z dd Zdddd ZddZddZddZddZddZddZddZddZddddZRS(icCsttjddS(sV Returns an array of volume objects Raises LsmError on error s Not supportedN(RRt NO_SUPPORT(RRRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolumesscCsttjddS(s Creates a volume, given a pool, volume name, size and provisioning Returns a tuple (job_id, new volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (Rtpoolt volume_namet size_bytest provisioningR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_creates cCsttjddS(sq Deletes a volume. Returns Job id or None if completed, else raises LsmError on errors. s Not supportedN(RRR (RtvolumeR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_deletescCsttjddS(s Re-sizes a volume. Returns a tuple (job_id, re-sized_volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (RR'tnew_size_bytesR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_resizescCsttjddS(sB Replicates a volume from the specified pool. In this library, to replicate means to create a new volume which is a copy of the source. Returns a tuple (job_id, replicated volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (RR"trep_typet volume_srctnameR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolume_replicates cCsttjddS(s@ Returns the number of bytes per block for volume_replicate_range call. Callers of volume_replicate_range need to use this when calculating start and block lengths. Note: bytes per block may not match volume blocksize. Returns bytes per block, Raises LsmError on error s Not supportedN(RRR (RRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt!volume_replicate_range_block_sizes cCsttjddS(s+ Replicates a portion of a volume to itself or another volume. The src, dest and number of blocks values change with vendor, call volume_replicate_range_block_size to get block unit size. Returns Job id or None if completed, else raises LsmError on errors. s Not supportedN(RRR (RR+R,t volume_desttrangesR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolume_replicate_ranges cCsttjddS(sx Makes a volume available to the host Returns None on success, else raises LsmError on errors. s Not supportedN(RRR (RR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_enablescCsttjddS(sz Makes a volume unavailable to the host Returns None on success, else raises LsmError on errors. s Not supportedN(RRR (RR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolume_disablescCsttjddS(s` Register a user/password for the specified initiator for CHAP authentication. in_user & in_password are for inbound CHAP, out_user & out_password are for outbound CHAP. Note: Setting in_user, in_password or out_user, out_password to None will disable authentication. Raises LsmError on error s Not supportedN(RRR (Rtinit_idtin_usert in_passwordtout_usert out_passwordR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytiscsi_chap_auths cCsttjddS(s~ Allows an access group to access a volume. Returns None on success, else raises LsmError on errors. s Not supportedN(RRR (Rt access_groupR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_maskscCsttjddS(s Revokes access for an access group for a volume Returns None on success, else raises LsmError on errors. s Not supportedN(RRR (RR;R'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_unmaskscCsttjddS(sM Returns a list of access groups, raises LsmError on errors. s Not supportedN(RRR (RRRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt access_groupsscCsttjddS(sM Returns a list of access groups, raises LsmError on errors. s Not supportedN(RRR (RR-R5t init_typeRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytaccess_group_createscCsttjddS(sC Deletes an access group, Raises LsmError on error s Not supportedN(RRR (RR;R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytaccess_group_deletescCsttjddS(sP Adds an initiator to an access group, Raises LsmError on error s Not supportedN(RRR (RR;R5R?R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytaccess_group_initiator_add scCsttjddS(sU Deletes an initiator from an access group, Raises LsmError on error s Not supportedN(RRR (RR;R5R?R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytaccess_group_initiator_deletescCsttjddS(so Returns the list of volumes that access group has access to. Raises LsmError on error s Not supportedN(RRR (RR;R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt"volumes_accessible_by_access_groupscCsttjddS(sw Returns the list of access groups that have access to the specified, Raises LsmError on error s Not supportedN(RRR (RR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytaccess_groups_granted_to_volume scCsttjddS(s Returns True if this volume has other volumes which are dependant on it. Implies that this volume cannot be deleted or possibly modified because it would affect its children. s Not supportedN(RRR (RR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolume_child_dependency'scCsttjddS(s If this volume has child dependency, this method call will fully replicate the blocks removing the relationship between them. This should return None (success) if volume_child_dependency would return False. Note: This operation could take a very long time depending on the size of the volume and the number of child dependencies. Returns None if complete else job id, raises LsmError on errors. s Not supportedN(RRR (RR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolume_child_dependency_rm/s cCsttjddS(Ns Not supported(RRR (RRRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt target_ports=sN(RRRR!R&R(R*R.R/R2R3R4R:R<R=R>R@RARBRCRDRERFRGRH(((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyRs,              tINetworkAttachedStoragecBseZdZddddZddZddZddZdddZdddZ ddZ dd Z dd Z e dd Zdd Zdd ZRS(sT Class the represents Network attached storage (Common NFS/CIFS operations) icCsdS(sf Returns a list of file systems on the controller. Raises LsmError on errors. N((RRRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfsEscCsttjddS(s WARNING: Destructive Deletes a file system and everything it contains Returns None on success, else job id s Not supportedN(RRR (RRJR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt fs_deleteLscCsttjddS(s Re-size a file system Returns a tuple (job_id, re-sized file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (RRJR)R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt fs_resizeUscCsttjddS(sO Creates a file system given a pool, name and size. Note: size is limited to 2**64 bytes so max size of a single volume at this time is 16 Exabytes Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (RR"R-R$R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt fs_create_s cCsttjddS(s# Creates a thin, point in time read/writable copy of src to dest. Optionally uses snapshot as backing of src_fs Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (Rtsrc_fst dest_fs_nametsnapshotR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_cloneks cCsttjddS(s Creates a thinly provisioned clone of src to dest. Note: Source and Destination are required to be on same filesystem Returns Job id or None if completed, else raises LsmError on errors. s Not supportedN(RRR (RRJt src_file_nametdest_file_nameRPR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt fs_file_clonevscCsttjddS(sl Returns a list of snapshots for the supplied file system, Raises LsmError on error s Not supportedN(RRR (RRJR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt fs_snapshotsscCsttjddS(s{ Snapshot is a point in time read-only copy Create a snapshot on the chosen file system Returns a tuple (job_id, snap shot created) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. Note: Snapshot name may not match what was passed in (depends on array implementation) s Not supportedN(RRR (RRJt snapshot_nameR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_snapshot_creates cCsttjddS(s Frees the re-sources for the given snapshot on the supplied filesystem. Returns Job id or None if completed, else raises LsmError on errors. s Not supportedN(RRR (RRJRPR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_snapshot_deletescCsttjddS(s< WARNING: Destructive! Reverts a file-system or just the specified files from the snapshot. If a list of files is supplied but the array cannot restore just them then the operation will fail with an LsmError raised. If files == None and all_files = True then all files on the file-system are restored. Restore_file if not None must be the same length as files with each index in each list referring to the associated file. Returns None on success, else job id, LsmError exception on error s Not supportedN(RRR (RRJRPtfilest restore_filest all_filesR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_snapshot_restorescCsttjddS(s& Returns True if the specified filesystem or specified file on this file system has child dependencies. This implies that this filesystem or specified file on this file system cannot be deleted or possibly modified because it would affect its children. s Not supportedN(RRR (RRJRYR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_child_dependencyscCsttjddS(s If this filesystem or specified file on this filesystem has child dependency this method will fully replicate the blocks removing the relationship between them. This should return None(success) if fs_child_dependency would return False. Note: This operation could take a very long time depending on the size of the filesystem and the number of child dependencies. Returns Job id or None if completed, else raises LsmError on errors. s Not supportedN(RRR (RRJRYR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_child_dependency_rms N(RRRRRJRKRLRMRQRTRURWRXtFalseR\R]R^(((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyRIAs      tINfscBs>eZddZddddZddZddZRS(icCsttjddS(sP Returns the types of authentication that are available for NFS s Not supportedN(RRR (RR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt export_authscCsttjddS(sL Get a list of all exported file systems on the controller. s Not supportedN(RRR (RRRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytexportssc CsttjddS(sA Exports a filesystem as specified in the export s Not supportedN(RRR ( Rtfs_idt export_patht root_listtrw_listtro_listtanon_uidtanon_gidt auth_typetoptionsR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt export_fsscCsttjddS(s. Removes the specified export s Not supportedN(RRR (RtexportR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt export_removesN(RRRaRRbRlRn(((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyR`s  N(tabcRt_ABCMetaRRtlsmRRtsixRtobjectRRRIR`(((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytsj_client.py000064400000235003147576505410006554 0ustar00# Copyright (C) 2011-2014 Red Hat, Inc. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: tasleson import os import sys from lsm import (Volume, NfsExport, Capabilities, Pool, System, Battery, Disk, AccessGroup, FileSystem, FsSnapshot, uri_parse, LsmError, ErrorNumber, INetworkAttachedStorage, TargetPort) from lsm._common import return_requires as _return_requires from lsm._common import UDS_PATH as _UDS_PATH from lsm._transport import TransPort as _TransPort from lsm._data import IData as _IData import six # Removes self for the hash d # @param d Hash to remove self from # @returns d with hash removed. def _del_self(d): """ Used to remove the self key from the dict d. Self is included when calling the function locals() in a class method. """ del d['self'] return d def _check_search_key(search_key, supported_keys): if search_key and search_key not in supported_keys: raise LsmError(ErrorNumber.UNSUPPORTED_SEARCH_KEY, "Unsupported search_key: '%s'" % search_key) return # Descriptive exception about daemon not running. def _raise_no_daemon(): raise LsmError(ErrorNumber.DAEMON_NOT_RUNNING, "The libStorageMgmt daemon is not running (process " "name lsmd), try 'service libstoragemgmt start'") # Main client class for library. # ** IMPORTANT ** # Theory of operation for methods in this class. # We are using the name of the method and the name of the parameters and # using python introspection abilities to translate them to the method and # parameter names. Makes the code compact, but you will break things if the # IPlugin class does not match the method names and parameters here! class Client(INetworkAttachedStorage): # # Used for default flag value # FLAG_RSVD = 0 FLAG_VOLUME_CREATE_USE_SYSTEM_CACHE = 1 << 0 FLAG_VOLUME_CREATE_USE_IO_PASSTHROUGH = 1 << 1 FLAG_VOLUME_CREATE_DISABLE_SYSTEM_CACHE = 1 << 2 FLAG_VOLUME_CREATE_DISABLE_IO_PASSTHROUGH = 1 << 3 """ Client side class used for managing storage that utilises RPC mechanism. """ # Method added so that the interface for the client RPC and the plug-in # itself match. def plugin_register(self, uri, plain_text_password, timeout_ms, flags=0): raise RuntimeError("Do not call directly!") # Called when we are ready to initialize the plug-in. # @param self The this pointer # @param uri The uniform resource identifier # @param plain_text_password Password as plain text # @param timeout_ms The timeout in ms # @param flags Reserved for future use, must be zero. # @returns None def __start(self, uri, password, timeout, flags=0): """ Instruct the plug-in to get ready """ self._tp.rpc('plugin_register', _del_self(locals())) # Checks to see if any unix domain sockets exist in the base directory # and opens a socket to one to see if the server is actually there. # @param self The this pointer # @returns True if daemon appears to be present, else false. @staticmethod def _check_daemon_exists(): uds_path = Client._plugin_uds_path() if os.path.exists(uds_path): for root, sub_folders, files in os.walk(uds_path): for filename in files: uds = os.path.join(root, filename) try: # This operation will work if the daemon is available s = _TransPort.get_socket(uds) s.close() return True except LsmError: pass else: # Base directory is not present? pass return False @staticmethod def _plugin_uds_path(): rc = _UDS_PATH if 'LSM_UDS_PATH' in os.environ: rc = os.environ['LSM_UDS_PATH'] return rc # Class constructor # @param self The this pointer # @param uri The uniform resource identifier # @param plain_text_password Password as plain text (Optional) # @param timeout_ms The timeout in ms # @param flags Reserved for future use, must be zero. # @returns None def __init__(self, uri, plain_text_password=None, timeout_ms=30000, flags=0): self._uri = uri self._password = plain_text_password self._timeout = timeout_ms self._uds_path = Client._plugin_uds_path() u = uri_parse(uri, ['scheme']) scheme = u['scheme'] if "+" in scheme: (plug, proto) = scheme.split("+") scheme = plug self.plugin_path = os.path.join(self._uds_path, scheme) if os.path.exists(self.plugin_path): self._tp = _TransPort(_TransPort.get_socket(self.plugin_path)) else: # At this point we don't know if the user specified an incorrect # plug-in in the URI or the daemon isn't started. We will check # the directory for other unix domain sockets. if Client._check_daemon_exists(): raise LsmError(ErrorNumber.PLUGIN_NOT_EXIST, "Plug-in %s not found!" % self.plugin_path) else: _raise_no_daemon() self.__start(uri, plain_text_password, timeout_ms, flags) # Synonym for close. @_return_requires(None) def plugin_unregister(self, flags=FLAG_RSVD): """ Synonym for close. """ self.close(flags) # Does an orderly plugin_unregister of the plug-in # @param self The this pointer # @param flags Reserved for future use, must be zero. @_return_requires(None) def close(self, flags=FLAG_RSVD): """ Does an orderly plugin_unregister of the plug-in """ self._tp.rpc('plugin_unregister', _del_self(locals())) self._tp.close() self._tp = None # Retrieves all the available plug-ins # @param field_sep Field separator # @param flags: Reserved for future use @staticmethod @_return_requires([six.string_types[0]]) def available_plugins(field_sep=':', flags=FLAG_RSVD): """ Retrieves all the available plug-ins Return list of strings of available plug-ins with the "descversion" """ rc = [] if not Client._check_daemon_exists(): _raise_no_daemon() uds_path = Client._plugin_uds_path() for root, sub_folders, files in os.walk(uds_path): for filename in files: uds = os.path.join(root, filename) tp = _TransPort(_TransPort.get_socket(uds)) i, v = tp.rpc('plugin_info', dict(flags=flags)) rc.append("%s%s%s" % (i, field_sep, v)) tp.close() return rc # Sets the timeout for the plug-in # @param self The this pointer # @param ms Time-out in ms # @param flags Reserved for future use, must be zero. @_return_requires(None) def time_out_set(self, ms, flags=FLAG_RSVD): """ Sets any time-outs for the plug-in (ms) Return None on success, else LsmError exception """ return self._tp.rpc('time_out_set', _del_self(locals())) # Retrieves the current time-out value. # @param self The this pointer # @param flags Reserved for future use, must be zero. # @returns Time-out value @_return_requires(int) def time_out_get(self, flags=FLAG_RSVD): """ Retrieves the current time-out Return time-out in ms, else raise LsmError """ return self._tp.rpc('time_out_get', _del_self(locals())) # Retrieves the status of the specified job id. # @param self The this pointer # @param job_id The job identifier # @param flags Reserved for future use, must be zero. # @returns A tuple ( status (enumeration), percent_complete, # completed item) @_return_requires(int, int, _IData) def job_status(self, job_id, flags=FLAG_RSVD): """ Returns the stats of the given job. Returns a tuple ( status (enumeration), percent_complete, completed item). else LsmError exception. """ return self._tp.rpc('job_status', _del_self(locals())) # Frees the resources for the specified job id. # @param self The this pointer # @param job_id Job id in which to release resource for # @param flags Reserved for future use, must be zero. @_return_requires(None) def job_free(self, job_id, flags=FLAG_RSVD): """ Frees resources for a given job number. Returns None on success, else raises an LsmError """ return self._tp.rpc('job_free', _del_self(locals())) # Gets the capabilities of the array. # @param self The this pointer # @param system The system of interest # @param flags Reserved for future use, must be zero. # @returns Capability object @_return_requires(Capabilities) def capabilities(self, system, flags=FLAG_RSVD): """ Fetches the capabilities of the array Returns a capability object, see data,py for details. """ return self._tp.rpc('capabilities', _del_self(locals())) # Gets information about the plug-in # @param self The this pointer # @param flags Reserved for future use # @returns Tuple (description, version) @_return_requires(six.string_types[0], six.string_types[0]) def plugin_info(self, flags=FLAG_RSVD): """ Returns a description and version of plug-in """ return self._tp.rpc('plugin_info', _del_self(locals())) # Returns an array of pool objects. # @param self The this pointer # @param search_key Search key # @param search_value Search value # @param flags Reserved for future use, must be zero. # @returns An array of pool objects. @_return_requires([Pool]) def pools(self, search_key=None, search_value=None, flags=FLAG_RSVD): """ Returns an array of pool objects. Pools are used in both block and file system interfaces, thus the reason they are in the base class. """ _check_search_key(search_key, Pool.SUPPORTED_SEARCH_KEYS) return self._tp.rpc('pools', _del_self(locals())) # Returns an array of system objects. # @param self The this pointer # @param flags Reserved for future use, must be zero. # @returns An array of system objects. @_return_requires([System]) def systems(self, flags=FLAG_RSVD): """ Returns an array of system objects. System information is used to distinguish resources from on storage array to another when the plug=in supports the ability to have more than one array managed by it """ return self._tp.rpc('systems', _del_self(locals())) # Changes the read cache percentage for a system. # @param self The this pointer # @param system System object to target # @param read_pct Desired read cache percentage # @param flags Flags # @returns None on success, else raises LsmError @_return_requires(None) def system_read_cache_pct_update(self, system, read_pct, flags=FLAG_RSVD): """ lsm.Client.system_read_cache_pct_update(self, system, read_pct, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: This method updates the read cache percentage on a system if supported Parameters: system(lsm.System) an lsm.System object. read_pct(int) the desired read cache percentage. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: returns None on success, else raises LsmError on errors. SpecialExceptions: """ if sys.version_info[0] == 2: if not isinstance(read_pct, (int, long)): raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Invalid read_pct, should be an integer") else: if not isinstance(read_pct, int): raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Invalid read_pct, should be an integer") if read_pct > 100 or read_pct < 0: raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Invalid read_pct, should be in range 0 - 100") return self._tp.rpc('system_read_cache_pct_update', _del_self(locals())) # Register a user/password for the specified initiator for CHAP # authentication. # Note: If you pass an empty user and password the expected behavior is to # remove any authentication for the specified initiator. # @param self The this pointer # @param init_id The initiator ID # @param in_user User for inbound CHAP # @param in_password Password for inbound CHAP # @param out_user Outbound username # @param out_password Outbound password # @param flags Reserved for future use, must be zero. # @returns None on success, throws LsmError on errors. @_return_requires(None) def iscsi_chap_auth(self, init_id, in_user, in_password, out_user, out_password, flags=FLAG_RSVD): """ Register a user/password for the specified initiator for CHAP authentication. """ AccessGroup.initiator_id_verify(init_id, AccessGroup.INIT_TYPE_ISCSI_IQN, raise_exception=True) return self._tp.rpc('iscsi_chap_auth', _del_self(locals())) # Returns an array of volume objects # @param self The this pointer # @param search_key Search key to use # @param search_value Search value # @param flags Reserved for future use, must be zero. # @returns An array of volume objects. @_return_requires([Volume]) def volumes(self, search_key=None, search_value=None, flags=FLAG_RSVD): """ Returns an array of volume objects """ _check_search_key(search_key, Volume.SUPPORTED_SEARCH_KEYS) return self._tp.rpc('volumes', _del_self(locals())) # Creates a volume # @param self The this pointer # @param pool The pool object to allocate storage from # @param volume_name The human text name for the volume # @param size_bytes Size of the volume in bytes # @param provisioning How the volume is to be provisioned # @param flags Reserved for future use, must be zero. # @returns A tuple (job_id, new volume), when one is None the other is # valid. @_return_requires(six.string_types[0], Volume) def volume_create(self, pool, volume_name, size_bytes, provisioning, flags=FLAG_RSVD): """ Creates a volume, given a pool, volume name, size and provisioning returns a tuple (job_id, new volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ return self._tp.rpc('volume_create', _del_self(locals())) # Re-sizes a volume # @param self The this pointer # @param volume The volume object to re-size # @param new_size_bytes Size of the volume in bytes # @param flags Reserved for future use, must be zero. # @returns A tuple (job_id, new re-sized volume), when one is # None the other is valid. @_return_requires(six.string_types[0], Volume) def volume_resize(self, volume, new_size_bytes, flags=FLAG_RSVD): """ Re-sizes a volume. Returns a tuple (job_id, re-sized_volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ return self._tp.rpc('volume_resize', _del_self(locals())) # Replicates a volume from the specified pool. # @param self The this pointer # @param pool The pool to re-size from # @param rep_type Replication type # (enumeration,see common.data.Volume) # @param volume_src The volume to replicate # @param name Human readable name of replicated volume # @param flags Reserved for future use, must be zero. # @returns A tuple (job_id, new replicated volume), when one is # None the other is valid. @_return_requires(six.string_types[0], Volume) def volume_replicate(self, pool, rep_type, volume_src, name, flags=FLAG_RSVD): """ Replicates a volume from the specified pool. Returns a tuple (job_id, replicated volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ return self._tp.rpc('volume_replicate', _del_self(locals())) # Size of a replicated block. # @param self The this pointer # @param system The system to request the rep. block range size from # @param flags Reserved for future use, must be zero # @returns Size of the replicated block in bytes @_return_requires(int) def volume_replicate_range_block_size(self, system, flags=FLAG_RSVD): """ Returns the size of a replicated block in bytes. """ return self._tp.rpc('volume_replicate_range_block_size', _del_self(locals())) # Replicates a portion of a volume to itself or another volume. # @param self The this pointer # @param rep_type Replication type # (enumeration, see common.data.Volume) # @param volume_src The volume src to replicate from # @param volume_dest The volume dest to replicate to # @param ranges An array of Block range objects # @see lsm.common.data.BlockRange # @param flags Reserved for future use, must be zero. # @returns Job id or None when completed, else raises LsmError on errors. @_return_requires(six.string_types[0]) def volume_replicate_range(self, rep_type, volume_src, volume_dest, ranges, flags=FLAG_RSVD): """ Replicates a portion of a volume to itself or another volume. The src, dest and number of blocks values change with vendor, call volume_replicate_range_block_size to get block unit size. Returns Job id or None when completed, else raises LsmError on errors. """ return self._tp.rpc('volume_replicate_range', _del_self(locals())) # Deletes a volume # @param self The this pointer # @param volume The volume object which represents the volume to delete # @param flags Reserved for future use, must be zero. # @returns None on success, else job id. Raises LsmError on errors. @_return_requires(six.string_types[0]) def volume_delete(self, volume, flags=FLAG_RSVD): """ Deletes a volume. Returns None on success, else job id """ return self._tp.rpc('volume_delete', _del_self(locals())) # Makes a volume online and available to the host. # @param self The this pointer # @param volume The volume to place online # @param flags Reserved for future use, must be zero. # @returns None on success, else raises LsmError @_return_requires(None) def volume_enable(self, volume, flags=FLAG_RSVD): """ Makes a volume available to the host returns None on success, else raises LsmError on errors. """ return self._tp.rpc('volume_enable', _del_self(locals())) # Takes a volume offline # @param self The this pointer # @param volume The volume object # @param flags Reserved for future use, must be zero. # @returns None on success, else raises LsmError on errors. @_return_requires(None) def volume_disable(self, volume, flags=FLAG_RSVD): """ Makes a volume unavailable to the host returns None on success, else raises LsmError on errors. """ return self._tp.rpc('volume_disable', _del_self(locals())) # Returns an array of disk objects # @param self The this pointer # @param search_key Search Key # @param search_value Search value # @param flags When equal to DISK.FLAG_RETRIEVE_FULL_INFO # returned objects will contain optional data. # If not defined, only the mandatory properties will # be returned. # @returns An array of disk objects. @_return_requires([Disk]) def disks(self, search_key=None, search_value=None, flags=FLAG_RSVD): """ Returns an array of disk objects """ _check_search_key(search_key, Disk.SUPPORTED_SEARCH_KEYS) return self._tp.rpc('disks', _del_self(locals())) # Access control for allowing an access group to access a volume # @param self The this pointer # @param access_group The access group # @param volume The volume to grant access to # @param flags Reserved for future use, must be zero. # @returns None on success, throws LsmError on errors. @_return_requires(None) def volume_mask(self, access_group, volume, flags=FLAG_RSVD): """ Allows an access group to access a volume. """ return self._tp.rpc('volume_mask', _del_self(locals())) # Revokes access to a volume to initiators in an access group # @param self The this pointer # @param access_group The access group # @param volume The volume to grant access to # @param flags Reserved for future use, must be zero. # @returns None on success, throws LsmError on errors. @_return_requires(None) def volume_unmask(self, access_group, volume, flags=FLAG_RSVD): """ Revokes access for an access group for a volume """ return self._tp.rpc('volume_unmask', _del_self(locals())) # Returns a list of access group objects # @param self The this pointer # @param search_key Search Key # @param search_value Search value # @param flags Reserved for future use, must be zero. # @returns List of access groups @_return_requires([AccessGroup]) def access_groups(self, search_key=None, search_value=None, flags=FLAG_RSVD): """ Returns a list of access groups """ _check_search_key(search_key, AccessGroup.SUPPORTED_SEARCH_KEYS) return self._tp.rpc('access_groups', _del_self(locals())) # Creates an access a group with the specified initiator in it. # @param self The this pointer # @param name The initiator group name # @param init_id Initiator id # @param init_type Type of initiator (Enumeration) # @param system Which system to create this group on # @param flags Reserved for future use, must be zero. # @returns AccessGroup on success, else raises LsmError @_return_requires(AccessGroup) def access_group_create(self, name, init_id, init_type, system, flags=FLAG_RSVD): """ Creates an access group and add the specified initiator id, init_type and desired access. """ init_type, init_id = AccessGroup.initiator_id_verify( init_id, init_type, raise_exception=True)[1:] return self._tp.rpc('access_group_create', _del_self(locals())) # Deletes an access group. # @param self The this pointer # @param access_group The access group to delete # @param flags Reserved for future use, must be zero. # @returns None on success, throws LsmError on errors. @_return_requires(None) def access_group_delete(self, access_group, flags=FLAG_RSVD): """ Deletes an access group """ return self._tp.rpc('access_group_delete', _del_self(locals())) # Adds an initiator to an access group # @param self The this pointer # @param access_group Group to add initiator to # @param init_id Initiators id # @param init_type Initiator id type (enumeration) # @param flags Reserved for future use, must be zero. # @returns None on success, throws LsmError on errors. @_return_requires(AccessGroup) def access_group_initiator_add(self, access_group, init_id, init_type, flags=FLAG_RSVD): """ Adds an initiator to an access group """ init_type, init_id = AccessGroup.initiator_id_verify( init_id, init_type, raise_exception=True)[1:] return self._tp.rpc('access_group_initiator_add', _del_self(locals())) # Deletes an initiator from an access group # @param self The this pointer # @param access_group The access group to remove initiator from # @param init_id The initiator to remove from the group # @param init_type Initiator id type (enumeration) # @param flags Reserved for future use, must be zero. # @returns None on success, throws LsmError on errors. @_return_requires(AccessGroup) def access_group_initiator_delete(self, access_group, init_id, init_type, flags=FLAG_RSVD): """ Deletes an initiator from an access group """ init_id = AccessGroup.initiator_id_verify(init_id, None, raise_exception=True)[2] return self._tp.rpc('access_group_initiator_delete', _del_self(locals())) # Returns the list of volumes that access group has access to. # @param self The this pointer # @param access_group The access group to list volumes for # @param flags Reserved for future use, must be zero. # @returns list of volumes @_return_requires([Volume]) def volumes_accessible_by_access_group(self, access_group, flags=FLAG_RSVD): """ Returns the list of volumes that access group has access to. """ return self._tp.rpc('volumes_accessible_by_access_group', _del_self(locals())) # Returns the list of access groups that have access to the specified # volume. # @param self The this pointer # @param volume The volume to list access groups for # @param flags Reserved for future use, must be zero. # @returns list of access groups @_return_requires([AccessGroup]) def access_groups_granted_to_volume(self, volume, flags=FLAG_RSVD): """ Returns the list of access groups that have access to the specified volume. """ return self._tp.rpc('access_groups_granted_to_volume', _del_self(locals())) # Checks to see if a volume has child dependencies. # @param self The this pointer # @param volume The volume to check # @param flags Reserved for future use, must be zero. # @returns True or False @_return_requires(bool) def volume_child_dependency(self, volume, flags=FLAG_RSVD): """ Returns True if this volume has other volumes which are dependant on it. Implies that this volume cannot be deleted or possibly modified because it would affect its children. """ return self._tp.rpc('volume_child_dependency', _del_self(locals())) # Removes any child dependency. # @param self The this pointer # @param volume The volume to remove dependencies for # @param flags Reserved for future use, must be zero. # @returns None if complete, else job id. @_return_requires(six.string_types[0]) def volume_child_dependency_rm(self, volume, flags=FLAG_RSVD): """ If this volume has child dependency, this method call will fully replicate the blocks removing the relationship between them. This should return None (success) if volume_child_dependency would return False. Note: This operation could take a very long time depending on the size of the volume and the number of child dependencies. Returns None if complete else job id, raises LsmError on errors. """ return self._tp.rpc('volume_child_dependency_rm', _del_self(locals())) # Returns a list of file system objects. # @param self The this pointer # @param search_key Search Key # @param search_value Search value # @param flags Reserved for future use, must be zero. # @returns A list of FS objects. @_return_requires([FileSystem]) def fs(self, search_key=None, search_value=None, flags=FLAG_RSVD): """ Returns a list of file systems on the controller. """ _check_search_key(search_key, FileSystem.SUPPORTED_SEARCH_KEYS) return self._tp.rpc('fs', _del_self(locals())) # Deletes a file system # @param self The this pointer # @param fs The file system to delete # @param flags Reserved for future use, must be zero. # @returns None on success, else job id @_return_requires(six.string_types[0]) def fs_delete(self, fs, flags=FLAG_RSVD): """ WARNING: Destructive Deletes a file system and everything it contains Returns None on success, else job id """ return self._tp.rpc('fs_delete', _del_self(locals())) # Re-sizes a file system # @param self The this pointer # @param fs The file system to re-size # @param new_size_bytes The new size of the file system in bytes # @param flags Reserved for future use, must be zero. # @returns tuple (job_id, re-sized file system), # When one is None the other is valid @_return_requires(six.string_types[0], FileSystem) def fs_resize(self, fs, new_size_bytes, flags=FLAG_RSVD): """ Re-size a file system Returns a tuple (job_id, re-sized file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ return self._tp.rpc('fs_resize', _del_self(locals())) # Creates a file system. # @param self The this pointer # @param pool The pool object to allocate space from # @param name The human text name for the file system # @param size_bytes The size of the file system in bytes # @param flags Reserved for future use, must be zero. # @returns tuple (job_id, file system), # When one is None the other is valid @_return_requires(six.string_types[0], FileSystem) def fs_create(self, pool, name, size_bytes, flags=FLAG_RSVD): """ Creates a file system given a pool, name and size. Note: size is limited to 2**64 bytes Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ return self._tp.rpc('fs_create', _del_self(locals())) # Clones a file system # @param self The this pointer # @param src_fs The source file system to clone # @param dest_fs_name The destination file system clone name # @param snapshot Optional, create clone from previous snapshot # @param flags Reserved for future use, must be zero. # @returns tuple (job_id, file system) @_return_requires(six.string_types[0], FileSystem) def fs_clone(self, src_fs, dest_fs_name, snapshot=None, flags=FLAG_RSVD): """ Creates a thin, point in time read/writable copy of src to dest. Optionally uses snapshot as backing of src_fs Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ return self._tp.rpc('fs_clone', _del_self(locals())) # Clones an individual file or files on the specified file system # @param self The this pointer # @param fs The file system the files are on # @param src_file_name The source file name # @param dest_file_name The dest. file name # @param snapshot Optional, the snapshot to base clone source # file from # @param flags Reserved for future use, must be zero. # @returns None on success, else job id @_return_requires(six.string_types[0]) def fs_file_clone(self, fs, src_file_name, dest_file_name, snapshot=None, flags=FLAG_RSVD): """ Creates a thinly provisioned clone of src to dest. Note: Source and Destination are required to be on same filesystem and all directories in destination path need to exist. Returns None on success, else job id """ return self._tp.rpc('fs_file_clone', _del_self(locals())) # Returns a list of snapshots # @param self The this pointer # @param fs The file system # @param flags Reserved for future use, must be zero. # @returns a list of snapshot objects. @_return_requires([FsSnapshot]) def fs_snapshots(self, fs, flags=FLAG_RSVD): """ Returns a list of snapshot names for the supplied file system """ return self._tp.rpc('fs_snapshots', _del_self(locals())) # Creates a snapshot (Point in time read only copy) # @param self The this pointer # @param fs The file system to snapshot # @param snapshot_name The human readable snapshot name # @param flags Reserved for future use, must be zero. # @returns tuple (job_id, snapshot) @_return_requires(six.string_types[0], FsSnapshot) def fs_snapshot_create(self, fs, snapshot_name, flags=FLAG_RSVD): """ Snapshot is a point in time read-only copy Create a snapshot on the chosen file system. Returns a tuple (job_id, snapshot) Notes: - Snapshot name may not match what was passed in (depends on array implementation) - Tuple return values are mutually exclusive, when one is None the other must be valid. """ return self._tp.rpc('fs_snapshot_create', _del_self(locals())) # Deletes a snapshot # @param self The this pointer # @param fs The filesystem the snapshot it for # @param snapshot The specific snap shot to delete # @param flags Reserved for future use, must be zero. # @returns None on success, else job id @_return_requires(six.string_types[0]) def fs_snapshot_delete(self, fs, snapshot, flags=FLAG_RSVD): """ Frees the re-sources for the given snapshot on the supplied filesystem. Returns None on success else job id, LsmError exception on error """ return self._tp.rpc('fs_snapshot_delete', _del_self(locals())) # Reverts a snapshot # @param self The this pointer # @param fs The file system object to restore snapshot for # @param snapshot The snapshot file to restore back too # @param files The specific files to restore # @param restore_files Individual files to restore # @param all_files Set to True if all files should be restored # back # @param flags Reserved for future use, must be zero. # @return None on success, else job id @_return_requires(six.string_types[0]) def fs_snapshot_restore(self, fs, snapshot, files, restore_files, all_files=False, flags=FLAG_RSVD): """ WARNING: Destructive! Reverts a file-system or just the specified files from the snapshot. If a list of files is supplied but the array cannot restore just them then the operation will fail with an LsmError raised. If files == None and all_files = True then all files on the file-system are restored. Restore_file if None none must be the same length as files with each index in each list referring to the associated file. Returns None on success, else job id, LsmError exception on error """ return self._tp.rpc('fs_snapshot_restore', _del_self(locals())) # Checks to see if a file system has child dependencies. # @param fs The file system to check # @param files The files to check (optional) # @param flags Reserved for future use, must be zero. # @returns True or False @_return_requires(bool) def fs_child_dependency(self, fs, files, flags=FLAG_RSVD): """ Returns True if the specified filesystem or specified file on this file system has child dependencies. This implies that this filesystem or specified file on this file system cannot be deleted or possibly modified because it would affect its children. """ return self._tp.rpc('fs_child_dependency', _del_self(locals())) # Removes child dependencies from a FS or specific file. # @param self The this pointer # @param fs The file system to remove child dependencies for # @param files The list of files to remove child dependencies (opt.) # @param flags Reserved for future use, must be zero. # @returns None if complete, else job id. @_return_requires(six.string_types[0]) def fs_child_dependency_rm(self, fs, files, flags=FLAG_RSVD): """ If this filesystem or specified file on this filesystem has child dependency this method will fully replicate the blocks removing the relationship between them. This should return None(success) if fs_child_dependency would return False. Note: This operation could take a very long time depending on the size of the filesystem and the number of child dependencies. Returns None if completed, else job id. Raises LsmError on errors. """ return self._tp.rpc('fs_child_dependency_rm', _del_self(locals())) # Returns a list of all the NFS client authentication types. # @param self The this pointer # @param flags Reserved for future use, must be zero. # @returns An array of client authentication types. @_return_requires([six.string_types[0]]) def export_auth(self, flags=FLAG_RSVD): """ What types of NFS client authentication are supported. """ return self._tp.rpc('export_auth', _del_self(locals())) # Returns a list of all the exported file systems # @param self The this pointer # @param search_key Search Key # @param search_value Search value # @param flags Reserved for future use, must be zero. # @returns An array of export objects @_return_requires([NfsExport]) def exports(self, search_key=None, search_value=None, flags=FLAG_RSVD): """ Get a list of all exported file systems on the controller. """ _check_search_key(search_key, NfsExport.SUPPORTED_SEARCH_KEYS) return self._tp.rpc('exports', _del_self(locals())) # Exports a FS as specified in the export. # @param self The this pointer # @param fs_id The FS ID to export # @param export_path The export path (Set to None for array to pick) # @param root_list List of hosts with root access # @param rw_list List of hosts with read/write access # @param ro_list List of hosts with read only access # @param anon_uid UID to map to anonymous # @param anon_gid GID to map to anonymous # @param auth_type NFS client authentication type # @param options Options to pass to plug-in # @param flags Reserved for future use, must be zero. # @returns NfsExport on success, else raises LsmError @_return_requires(NfsExport) def export_fs(self, fs_id, export_path, root_list, rw_list, ro_list, anon_uid=NfsExport.ANON_UID_GID_NA, anon_gid=NfsExport.ANON_UID_GID_NA, auth_type=None, options=None, flags=FLAG_RSVD): """ Exports a filesystem as specified in the arguments """ if set(rw_list) - (set(rw_list) - set(ro_list)): raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Host cannot both in rw_list and ro_list.") return self._tp.rpc('export_fs', _del_self(locals())) # Removes the specified export # @param self The this pointer # @param export The export to remove # @param flags Reserved for future use, must be zero. # @returns None on success, else raises LsmError @_return_requires(None) def export_remove(self, export, flags=FLAG_RSVD): """ Removes the specified export """ return self._tp.rpc('export_remove', _del_self(locals())) # Returns a list of target ports # @param self The this pointer # @param search_key The key to search against # @param search_value The value to search for # @param flags Reserved for future use, must be zero # @returns List of target ports, else raises LsmError @_return_requires([TargetPort]) def target_ports(self, search_key=None, search_value=None, flags=FLAG_RSVD): """ Returns a list of target ports """ _check_search_key(search_key, TargetPort.SUPPORTED_SEARCH_KEYS) return self._tp.rpc('target_ports', _del_self(locals())) # Returns the RAID information of certain volume # @param self The this pointer # @param volume The volume to retrieve RAID information for # @param flags Reserved for future use, must be zero # @returns [raid_type, strip_size, disk_count, min_io_size, opt_io_size], # else raises LsmError @_return_requires([int, int, int, int, int]) def volume_raid_info(self, volume, flags=FLAG_RSVD): """Query the RAID information of certain volume. New in version 1.2. Query the RAID type, strip size, extents count, minimum I/O size, optimal I/O size of given volume. This method requires this capability: lsm.Capabilities.VOLUME_RAID_INFO Args: volume (Volume object): Volume to query flags (int): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: [raid_type, strip_size, disk_count, min_io_size, opt_io_size] raid_type (int): RAID Type of requested volume. Could be one of these values: Volume.RAID_TYPE_RAID0 Stripe Volume.RAID_TYPE_RAID1 Two disks Mirror Volume.RAID_TYPE_RAID3 Byte-level striping with dedicated parity Volume.RAID_TYPE_RAID4 Block-level striping with dedicated parity Volume.RAID_TYPE_RAID5 Block-level striping with distributed parity Volume.RAID_TYPE_RAID6 Block-level striping with two distributed parities, aka, RAID-DP Volume.RAID_TYPE_RAID10 Stripe of mirrors Volume.RAID_TYPE_RAID15 Parity of mirrors Volume.RAID_TYPE_RAID16 Dual parity of mirrors Volume.RAID_TYPE_RAID50 Stripe of parities Volume.RAID_TYPE_RAID60 Stripe of dual parities Volume.RAID_TYPE_RAID51 Mirror of parities Volume.RAID_TYPE_RAID61 Mirror of dual parities Volume.RAID_TYPE_JBOD Just bunch of disks, no parity, no striping. Volume.RAID_TYPE_UNKNOWN The plugin failed to detect the volume's RAID type. Volume.RAID_TYPE_MIXED This volume contains multiple RAID settings. Volume.RAID_TYPE_OTHER Vendor specific RAID type strip_size(int): The size of strip on each disk or other storage extent. For RAID1/JBOD, it should be set as sector size. If plugin failed to detect strip size, it should be set as Volume.STRIP_SIZE_UNKNOWN(0). disk_count(int): The count of disks used for assembling the RAID group(s) where this volume allocated from. For any RAID system using the slice of disk, this value indicate how many disk slices are used for the RAID. For example, on LVM RAID, the 'disk_count' here indicate the count of PVs used for certain volume. Another example, on EMC VMAX, the 'disk_count' here indicate how many hyper volumes are used for this volume. For any RAID system using remote LUN for data storing, each remote LUN should be count as a disk. If the plugin failed to detect disk_count, it should be set as Volume.DISK_COUNT_UNKNOWN(0). min_io_size(int): The minimum I/O size, device preferred I/O size for random I/O. Any I/O size not equal to a multiple of this value may get significant speed penalty. Normally it refers to strip size of each disk(extent). If plugin failed to detect min_io_size, it should try these values in the sequence of: logical sector size -> physical sector size -> Volume.MIN_IO_SIZE_UNKNOWN(0). opt_io_size(int): The optimal I/O size, device preferred I/O size for sequential I/O. Normally it refers to RAID group stripe size. If plugin failed to detect opt_io_size, it should be set to Volume.OPT_IO_SIZE_UNKNOWN(0). Raises: LsmError: ErrorNumber.NO_SUPPORT No support. """ return self._tp.rpc('volume_raid_info', _del_self(locals())) # Query the membership information of specified pool # @param self The this pointer # @param pool The pool to query # @param flags Reserved for future use, must be zero # @returns [raid_type, member_type, [member_ids]], lsmError on error @_return_requires([int, int, [six.string_types[0]]]) def pool_member_info(self, pool, flags=FLAG_RSVD): """ lsm.Client.pool_member_info(self, pool, flags=lsm.Client.FLAG_RSVD) Version: 1.2 Usage: Query the membership information of certain pool: RAID type, member type and member ids. Currently, LibStorageMgmt supports two types of pool: * Sub-pool -- Pool.MEMBER_TYPE_POOL Pool space is allocated from parent pool. Example: * NetApp ONTAP volume * Disk RAID pool -- Pool.MEMBER_TYPE_DISK Pool is a RAID group assembled by disks. Example: * LSI MegaRAID disk group * EMC VNX pool * NetApp ONTAP aggregate Parameters: pool (lsm.Pool object) Pool to query flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: [raid_type, member_type, member_ids] raid_type (int) RAID Type of requested pool. Could be one of these values: Volume.RAID_TYPE_RAID0 Stripe Volume.RAID_TYPE_RAID1 Two disks Mirror Volume.RAID_TYPE_RAID3 Byte-level striping with dedicated parity Volume.RAID_TYPE_RAID4 Block-level striping with dedicated parity Volume.RAID_TYPE_RAID5 Block-level striping with distributed parity Volume.RAID_TYPE_RAID6 Block-level striping with two distributed parities, aka, RAID-DP Volume.RAID_TYPE_RAID10 Stripe of mirrors Volume.RAID_TYPE_RAID15 Parity of mirrors Volume.RAID_TYPE_RAID16 Dual parity of mirrors Volume.RAID_TYPE_RAID50 Stripe of parities Volume.RAID_TYPE_RAID60 Stripe of dual parities Volume.RAID_TYPE_RAID51 Mirror of parities Volume.RAID_TYPE_RAID61 Mirror of dual parities Volume.RAID_TYPE_JBOD Just bunch of disks, no parity, no striping. Volume.RAID_TYPE_UNKNOWN The plugin failed to detect the volume's RAID type. Volume.RAID_TYPE_MIXED This pool contains multiple RAID settings. Volume.RAID_TYPE_OTHER Vendor specific RAID type member_type (int) Could be one of these values: Pool.MEMBER_TYPE_POOL Current pool(also known as sub-pool) is allocated from other pool(parent pool). The 'raid_type' will set to RAID_TYPE_OTHER unless certain RAID system support RAID using space of parent pools. Pool.MEMBER_TYPE_DISK Pool is created from RAID group using whole disks. Pool.MEMBER_TYPE_OTHER Vendor specific RAID member type. Pool.MEMBER_TYPE_UNKNOWN Plugin failed to detect the RAID member type. member_ids (list of strings) When 'member_type' is Pool.MEMBER_TYPE_POOL, the 'member_ids' will contain a list of parent Pool IDs. When 'member_type' is Pool.MEMBER_TYPE_DISK, the 'member_ids' will contain a list of disk IDs. When 'member_type' is Pool.MEMBER_TYPE_OTHER or Pool.MEMBER_TYPE_UNKNOWN, the member_ids should be an empty list. SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_POOL Capability: lsm.Capabilities.POOL_MEMBER_INFO """ return self._tp.rpc('pool_member_info', _del_self(locals())) # Queries all the supported RAID types and stripe sizes which could be # used for input into volume_raid_create # @param self The this pointer # @param system System (raid) card to query # @param flags Reserved for future use, must be zero # @returns [raid_types, strip_sizes], lsmError on error @_return_requires([[int], [int]]) def volume_raid_create_cap_get(self, system, flags=FLAG_RSVD): """ lsm.Client.volume_raid_create_cap_get( self, system, flags=lsm.Client.FLAG_RSVD) Version: 1.2 Usage: This method is dedicated to local hardware RAID cards. Query out all supported RAID types and strip sizes which could be used by lsm.Client.volume_raid_create() method. Parameters: system (lsm.System) Instance of lsm.System flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: [raid_types, strip_sizes] raid_types ([int]) List of integer, possible values are: Volume.RAID_TYPE_RAID0 Volume.RAID_TYPE_RAID1 Volume.RAID_TYPE_RAID5 Volume.RAID_TYPE_RAID6 Volume.RAID_TYPE_RAID10 Volume.RAID_TYPE_RAID50 Volume.RAID_TYPE_RAID60 strip_sizes ([int]) List of integer. Stripe size in bytes. SpecialExceptions: LsmError lsm.ErrorNumber.NO_SUPPORT Method not supported. Sample: lsm_client = lsm.Client('sim://') lsm_sys = lsm_client.systems()[0] disks = lsm_client.disks( search_key='system_id', search_value=lsm_sys.id) free_disks = [d for d in disks if d.status == Disk.STATUS_FREE] supported_raid_types, supported_strip_sizes = \ lsm_client.volume_raid_create_cap_get(lsm_sys) new_vol = lsm_client.volume_raid_create( 'test_volume_raid_create', supported_raid_types[0], free_disks, supported_strip_sizes[0]) Capability: lsm.Capabilities.VOLUME_CREATE_RAID This method is mandatory when volume_raid_create() is supported. """ return self._tp.rpc('volume_raid_create_cap_get', _del_self(locals())) # Create a disk RAID pool and allocate entire storage space to new volume # @param self The this pointer # @param name Name of the raid to be created # @param raid_type The raid type (enumerated) of the raid group # @param disks List of disk objects to use # @param strip_size Strip size in bytes # @param flags Flags # @returns the newly created volume, lsmError on errors @_return_requires(Volume) def volume_raid_create(self, name, raid_type, disks, strip_size, flags=FLAG_RSVD): """ lsm.Client.volume_raid_create(self, name, raid_type, disks, strip_size, flags=lsm.Client.FLAG_RSVD) Version: 1.2 Usage: This method is dedicated to local hardware RAID cards. Create a disk RAID pool and allocate entire storage space to new volume using requested volume name. When dealing with RAID10, 50 or 60, the first half part of 'disks' will be located in one bottom layer RAID group. The new volume and new pool will created within the same system of provided disks. This method does not allow duplicate call, when duplicate call was issued, LsmError with ErrorNumber.DISK_NOT_FREE will be raise. User should check disk.status for Disk.STATUS_FREE before invoking this method. Parameters: name (string) The name for new volume. The requested volume name might be ignored due to restriction of hardware RAID vendors. The pool name will be automatically chosen by plugin. raid_type (int) The RAID type for the RAID group, possible values are: Volume.RAID_TYPE_RAID0 Volume.RAID_TYPE_RAID1 Volume.RAID_TYPE_RAID5 Volume.RAID_TYPE_RAID6 Volume.RAID_TYPE_RAID10 Volume.RAID_TYPE_RAID15 Volume.RAID_TYPE_RAID16 Volume.RAID_TYPE_RAID50 Please check volume_raid_create_cap_get() returns to get supported all raid types of current hardware RAID card. disks ([lsm.Disks,]) A list of lsm.Disk objects. Free disks used for new RAID group. strip_size (int) The size in bytes of strip. When setting strip_size to Volume.VCR_STRIP_SIZE_DEFAULT, it allow hardware RAID cards to choose their default value. Please use volume_raid_create_cap_get() method to get all supported strip size of current hardware RAID card. The Volume.VCR_STRIP_SIZE_DEFAULT is always supported when lsm.Capabilities.VOLUME_CREATE_RAID is supported. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: lsm.Volume The lsm.Volume object for newly created volume. SpecialExceptions: LsmError lsm.ErrorNumber.NO_SUPPORT Method not supported or RAID type not supported. lsm.ErrorNumber.DISK_NOT_FREE Disk is not in Disk.STATUS_FREE status. lsm.ErrorNumber.NOT_FOUND_DISK Disk not found lsm.ErrorNumber.INVALID_ARGUMENT 1. Invalid input argument data. 2. Disks are not from the same system. 3. Disks are not from the same enclosure. 4. Invalid strip_size. 5. Disk count are meet the minimum requirement: RAID1: len(disks) == 2 RAID5: len(disks) >= 3 RAID6: len(disks) >= 4 RAID10: len(disks) % 2 == 0 and len(disks) >= 4 RAID50: len(disks) % 2 == 0 and len(disks) >= 6 RAID60: len(disks) % 2 == 0 and len(disks) >= 8 lsm.ErrorNumber.NAME_CONFLICT Requested name is already be used by other volume. Sample: lsm_client = lsm.Client('sim://') disks = lsm_client.disks() free_disks = [d for d in disks if d.status == Disk.STATUS_FREE] new_vol = lsm_client.volume_raid_create( 'raid0_vol1', Volume.RAID_TYPE_RAID0, free_disks) Capability: lsm.Capabilities.VOLUME_CREATE_RAID Indicate current system support volume_raid_create() method. At least one RAID type should be supported. The strip_size == Volume.VCR_STRIP_SIZE_DEFAULT is supported. """ if len(disks) == 0: raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Illegal input disks argument: no disk included") if raid_type == Volume.RAID_TYPE_RAID1 and len(disks) != 2: raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Illegal input disks argument: RAID 1 only allow 2 disks") if raid_type == Volume.RAID_TYPE_RAID5 and len(disks) < 3: raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Illegal input disks argument: RAID 5 require 3 or more disks") if raid_type == Volume.RAID_TYPE_RAID6 and len(disks) < 4: raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Illegal input disks argument: RAID 6 require 4 or more disks") if raid_type == Volume.RAID_TYPE_RAID10: if len(disks) % 2 or len(disks) < 4: raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Illegal input disks argument: " "RAID 10 require even disks count and 4 or more disks") if raid_type == Volume.RAID_TYPE_RAID50: if len(disks) % 2 or len(disks) < 6: raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Illegal input disks argument: " "RAID 50 require even disks count and 6 or more disks") if raid_type == Volume.RAID_TYPE_RAID60: if len(disks) % 2 or len(disks) < 8: raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Illegal input disks argument: " "RAID 60 require even disks count and 8 or more disks") return self._tp.rpc('volume_raid_create', _del_self(locals())) # Enable the IDENT LED for a volume. # @param self The this pointer # @param volume Volume object to target # @param flags Flags # @returns None on success, else raises LsmError @_return_requires(None) def volume_ident_led_on(self, volume, flags=FLAG_RSVD): """ lsm.Client.volume_ident_led_on(self, volume, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: This method enables the IDENT LED on a volume if supported Parameters: volume (lsm.Volume) An lsm.Volume object. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: returns None on success, else raises LsmError on errors. SpecialExceptions: """ return self._tp.rpc('volume_ident_led_on', _del_self(locals())) # Disable the IDENT LED for a volume. # @param self The this pointer # @param volume Volume object to target # @param flags Flags # @returns None on success, else raises LsmError @_return_requires(None) def volume_ident_led_off(self, volume, flags=FLAG_RSVD): """ lsm.Client.volume_ident_led_off(self, volume, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: This method disables the IDENT LED on a volume if supported Parameters: volume (lsm.Volume) An lsm.Volume object. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: returns None on success, else raises LsmError on errors. SpecialExceptions: """ return self._tp.rpc('volume_ident_led_off', _del_self(locals())) @_return_requires([Battery]) def batteries(self, search_key=None, search_value=None, flags=FLAG_RSVD): """ lsm.Client.batteries(self, search_key=None, search_value=None, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Query batteries. When present, super capacitors will also be included. Parameters: search_key (string, optional) The key name for the search. Valid search keys are stored in lsm.Battery.SUPPORTED_SEARCH_KEYS search_value (string, optional) The value of search_key to match. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: [lsm.Battery] lsm.Battery (object) lsm.Battery.id (string) Unique ID for this cache hardware. lsm.Battery.name (string) Human friendly name, might include physical location, model name and etc. lsm.Battery.type (int) The hardware type of cache. Could be one of these values: lsm.Battery.TYPE_CHEMICAL Chemical battery. lsm.Battery.TYPE_CAPACITOR Supper capacitor. lsm.Battery.TYPE_OTHER Vendor specific battery type. lsm.Battery.TYPE_UNKNOWN Unknown type. lsm.Battery.status (int, bitmap) Could be any combination of these values: lsm.Battery.STATUS_OK Battery is fully charged, health and not in use currently. lsm.Battery.STATUS_DISCHARGING Battery is in use. lsm.Battery.STATUS_CHARGING Battery is charging. lsm.Battery.STATUS_LEARNING Battery is calibrating itself by discharging battery and recharging again. lsm.Battery.STATUS_DEGRADED Battery is in degraded mode, need attention. For example, battery is near end of life. lsm.Battery.STATUS_ERROR Battery is having hardware error or end of life. lsm.Battery.STATUS_OTHER Vendor specific status. lsm.Battery.STATUS_UNKNOWN Unknown. lsm.Battery.system_id (string) The id of system which current battery belong to. SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT Capability: lsm.Capabilities.BATTERIES """ _check_search_key(search_key, Battery.SUPPORTED_SEARCH_KEYS) return self._tp.rpc('batteries', _del_self(locals())) @_return_requires([int, int, int, int, int]) def volume_cache_info(self, volume, flags=FLAG_RSVD): """ lsm.Client.volume_cache_info(self, volume, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Query RAM cache setting and status of specified volume on read and write I/O. Parameters: volume (Lsm.Volume) The lsm.Volume instance. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: [int, int, int, int, int] write_cache_policy (int) The write cache policy. Valid values are: * lsm.Volume.WRITE_CACHE_POLICY_WRITE_BACK The storage system will use write back mode if cache hardware found. * lsm.Volume.WRITE_CACHE_POLICY_AUTO The controller will use write back mode when battery/capacitor is in good health, otherwise, write through mode. * lsm.Volume.WRITE_CACHE_POLICY_WRITE_THROUGH The storage system will use write through mode. * lsm.Volume.WRITE_CACHE_POLICY_UNKNOWN Plugin failed to detect this setting. write_cache_status (int) The status of write cache. Valid values are: * lsm.Volume.WRITE_CACHE_STATUS_WRITE_THROUGH * lsm.Volume.WRITE_CACHE_STATUS_WRITE_BACK * lsm.Volume.WRITE_CACHE_STATUS_UNKNOWN read_cache_policy (int) The policy for read cache. Valid values are: * lsm.Volume.READ_CACHE_POLICY_ENABLED Read cache is enabled, when reading I/O on previous unchanged written I/O or read I/O in cache will be returned to I/O initiator immediately without checking backing store(normally disk). * lsm.Volume.READ_CACHE_POLICY_DISABLED Read cache is disabled. * lsm.Volume.READ_CACHE_POLICY_UNKNOWN Plugin failed to detect the read cache policy. read_cache_status (int) The status of read cache. Valid values are: * lsm.Volume.READ_CACHE_STATUS_ENABLED * lsm.Volume.READ_CACHE_STATUS_DISABLED * lsm.Volume.READ_CACHE_STATUS_UNKNOWN physical_disk_cache (int) Whether physical disk's cache is enabled or not. Please be advised, HDD's physical disk ram cache might be not protected by storage system's battery or capacitor on sudden power loss, you could lose data if a power failure occurs during a write process. For SSD's physical disk cache, please check with the vendor of your hardware RAID card and SSD disk. Valid values are: * lsm.Volume.PHYSICAL_DISK_CACHE_ENABLED Physical disk cache enabled. * lsm.Volume.PHYSICAL_DISK_CACHE_DISABLED Physical disk cache disabled. * lsm.Volume.PHYSICAL_DISK_CACHE_USE_DISK_SETTING Physical disk cache is determined by the disk vendor via physical disks' SCSI caching mode page(0x08 page). It is strongly suggested to change this value to lsm.Volume.PHYSICAL_DISK_CACHE_ENABLED or lsm.Volume.PHYSICAL_DISK_CACHE_DISABLED * lsm.Volume.PHYSICAL_DISK_CACHE_UNKNOWN Plugin failed to detect the physical disk status. SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_CACHE_INFO """ return self._tp.rpc('volume_cache_info', _del_self(locals())) @_return_requires(None) def volume_physical_disk_cache_update(self, volume, pdc, flags=FLAG_RSVD): """ lsm.Client.volume_physical_disk_cache_update(self, volume, pdc, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Change the setting of RAM physical disk cache of specified volume. On some product(like HPE SmartArray), this action will be effective at system level which means that even you are requesting a change on a specified volume, this change will apply to all other volumes on the same controller(system). Parameters: volume (Lsm.Volume) The lsm.Volume instance. pdc (int) lsm.Volume.PHYSICAL_DISK_CACHE_ENABLED Enable physical disk cache. lsm.Volume.PHYSICAL_DISK_CACHE_DISABLED Disable physical disk cache flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: N/A SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT You might also get NO_SUPPORT error when trying to change SSD physical disk cache on MegaRAID. ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_PHYSICAL_DISK_CACHE_SET Allow changing physical disk cache. lsm.Capabilities.VOLUME_PHYSICAL_DISK_CACHE_SET_SYSTEM_LEVEL Indicate that this action will change system settings which are effective on all volumes in this storage system. For example, on HPE SmartArray, the physical disk cache setting is a controller level setting. """ if (pdc != Volume.PHYSICAL_DISK_CACHE_ENABLED) and \ (pdc != Volume.PHYSICAL_DISK_CACHE_DISABLED): raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Argument pdc should be " "Volume.PHYSICAL_DISK_CACHE_ENABLED or " "Volume.PHYSICAL_DISK_CACHE_DISABLED") return self._tp.rpc('volume_physical_disk_cache_update', _del_self(locals())) @_return_requires(None) def volume_write_cache_policy_update(self, volume, wcp, flags=FLAG_RSVD): """ lsm.Client.volume_write_cache_policy_update(self, volume, wcp, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Change the RAM write cache policy on specified volume. If lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_IMPACT_READ is supported(e.g. HPE SmartArray), the changes on write cache policy might also impact read cache policy. If lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WB_IMPACT_OTHER is supported(e.g. HPE SmartArray), changing write cache policy to write back mode might impact other volumes in the same system. Parameters: volume (Lsm.Volume) The lsm.Volume instance. wcp (int) Could be one of these value: * lsm.Volume.WRITE_CACHE_POLICY_WRITE_BACK Change to write back mode. * lsm.Volume.WRITE_CACHE_POLICY_AUTO Change to auto mode: use write back mode when battery/capacitor is healthy, otherwise use write through. * lsm.Volume.WRITE_CACHE_POLICY_WRITE_THROUGH Change to write through mode. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: N/A SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WRITE_BACK Allow changing to always mode. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_AUTO Allow changing to auto mode. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WRITE_THROUGH Allow changing to disable mode. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_IMPACT_READ Indicate this action might impact read cache policy. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WB_IMPACT_OTHER Indicate that changing to write back mode might impact other volumes. For example, on HPE SmartArray, changing to write back mode will change all other volumes with auto write cache policy to write back mode. """ if wcp != Volume.WRITE_CACHE_POLICY_WRITE_BACK and \ wcp != Volume.WRITE_CACHE_POLICY_AUTO and \ wcp != Volume.WRITE_CACHE_POLICY_WRITE_THROUGH: raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Argument wcp should be " "Volume.WRITE_CACHE_POLICY_WRITE_BACK or " "Volume.WRITE_CACHE_POLICY_AUTO or " "Volume.WRITE_CACHE_POLICY_WRITE_THROUGH") return self._tp.rpc('volume_write_cache_policy_update', _del_self(locals())) @_return_requires(None) def volume_read_cache_policy_update(self, volume, rcp, flags=FLAG_RSVD): """ lsm.Client.volume_read_cache_policy_update(self, volume, rcp, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Change the RAM read cache policy of specified volume. If lsm.Capabilities.VOLUME_READ_CACHE_POLICY_SET_IMPACT_WRITE is supported(like HPE SmartArray), the change on write cache policy might also impact read cache policy. Parameters: volume (Lsm.Volume) The lsm.Volume instance. rcp (int) Could be one of these value: * lsm.Volume.READ_CACHE_POLICY_ENABLED Enable read cache. * lsm.Volume.READ_CACHE_POLICY_DISABLED Disable read cache. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: N/A SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_READ_CACHE_POLICY_SET Allow enabling or disabling read cache policy. lsm.Capabilities.VOLUME_READ_CACHE_POLICY_SET_IMPACT_WRITE Indicate that changing read cache policy might impact write cache policy. For example, on HPE SmartArray, disabling read cache will also change write cache policy to write through. """ if rcp != Volume.READ_CACHE_POLICY_ENABLED and \ rcp != Volume.READ_CACHE_POLICY_DISABLED: raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Argument rcp should be " "Volume.READ_CACHE_POLICY_ENABLED or " "Volume.READ_CACHE_POLICY_DISABLED") return self._tp.rpc('volume_read_cache_policy_update', _del_self(locals())) __init__.pyc000064400000002356147576505410007044 0ustar00 -P`c@sddlmZddlmZmZmZmZmZmZm Z m Z m Z m Z m Z mZddlmZddlmZmZmZmZmZmZmZmZmZmZmZmZddlmZm Z m!Z!m"Z"ddl#m$Z$ddl%m&Z&m'Z'gZ(dS( i(tVERSION( terrortinfotLsmErrort ErrorNumbert JobStatust uri_parsetmd5tProxytsize_bytes_2_size_humantcommon_urllib2_error_handlertsize_human_2_size_bytestint_div(t LocalDisk( tDisktVolumetPooltSystemt FileSystemt FsSnapshott NfsExportt BlockRanget AccessGroupt TargetPortt CapabilitiestBattery(tIPlugintIStorageAreaNetworktINetworkAttachedStoragetINfs(tClient(t PluginRunnertsearch_propertyN()t lsm.versionRt lsm._commonRRRRRRRRR R R R tlsm._local_diskR t lsm._dataRRRRRRRRRRRRt lsm._ipluginRRRRt lsm._clientRtlsm._pluginrunnerRR t__all__(((s0/usr/lib/python2.7/site-packages/lsm/__init__.pytsRR"external/__init__.py000064400000000000147576505410010503 0ustar00external/__init__.pyc000064400000000220147576505410010652 0ustar00 -P`c@sdS(N((((s9/usr/lib/python2.7/site-packages/lsm/external/__init__.pytsexternal/xmltodict.py000064400000010566147576505410010775 0ustar00# This code taken from recipe # http://code.activestate.com/recipes/ # 573463-converting-xml-to-dictionary-and-back/ # Modified slightly to remove namespace and number of other small details # Licensed: PSF from xml.etree import ElementTree def _ns(tag): return tag[tag.find('}') + 1:] class XmlDictObject(dict): """ Adds object like functionality to the standard dictionary. """ def __init__(self, initdict=None): if initdict is None: initdict = {} dict.__init__(self, initdict) def __getattr__(self, item): return self.__getitem__(item) def __setattr__(self, item, value): self.__setitem__(item, value) def __str__(self): if '_text' in self: return self.__getitem__('_text') else: return '' @staticmethod def wrap(x): """ Static method to wrap a dictionary recursively as an XmlDictObject """ if isinstance(x, dict): return XmlDictObject( (k, XmlDictObject.wrap(v)) for (k, v) in x.items()) elif isinstance(x, list): return [XmlDictObject.wrap(v) for v in x] else: return x @staticmethod def _un_wrap(x): if isinstance(x, dict): return dict( (k, XmlDictObject._un_wrap(v)) for (k, v) in x.items()) elif isinstance(x, list): return [XmlDictObject._un_wrap(v) for v in x] else: return x def un_wrap(self): """ Recursively converts an XmlDictObject to a standard dictionary and returns the result. """ return XmlDictObject._un_wrap(self) def _convert_dict_to_xml_recurse(parent, dictitem): assert isinstance(dictitem, dict) if isinstance(dictitem, dict): for (tag, child) in dictitem.items(): if str(tag) == '_text': parent.text = str(child) elif isinstance(child, list): # iterate through the array and convert for listchild in child: elem = ElementTree.Element(tag) parent.append(elem) _convert_dict_to_xml_recurse(elem, listchild) else: elem = ElementTree.Element(tag) parent.append(elem) _convert_dict_to_xml_recurse(elem, child) else: parent.text = str(dictitem) def convert_dict_to_xml(xmldict): """ Converts a dictionary to an XML ElementTree Element """ roottag = list(xmldict.keys())[0] root = ElementTree.Element(roottag) _convert_dict_to_xml_recurse(root, xmldict[roottag]) return root def _convert_xml_to_dict_recurse(node, dictclass): nodedict = dictclass() if len(list(node.items())) > 0: # if we have attributes, set them if'attrib' in nodedict: nodedict['attrib'].update(dict(list(node.items()))) else: nodedict['attrib'] = {} nodedict['attrib'].update(dict(list(node.items()))) # We get a collision so attributes get their own hash! # nodedict.update(dict(node.items())) for child in node: # recursively add the element's children newitem = _convert_xml_to_dict_recurse(child, dictclass) if _ns(child.tag) in nodedict: # found duplicate tag, force a list if isinstance(nodedict[_ns(child.tag)], list): # append to existing list nodedict[_ns(child.tag)].append(newitem) else: # convert to list nodedict[_ns(child.tag)] = [nodedict[_ns(child.tag)], newitem] else: # only one, directly set the dictionary nodedict[_ns(child.tag)] = newitem if node.text is None: text = None else: text = node.text.strip() if len(nodedict) > 0: # if we have a dictionary add the text as a dictionary value # (if there is any) if text is not None and len(text) > 0: nodedict['_text'] = text else: # if we don't have child nodes or attributes, just set the text nodedict = text return nodedict def convert_xml_to_dict(root, dictclass=XmlDictObject): """ Converts an ElementTree Element to a dictionary """ return dictclass( {_ns(root.tag): _convert_xml_to_dict_recurse(root, dictclass)}) external/xmltodict.pyc000064400000011653147576505410011136 0ustar00 -P`c@sZddlmZdZdefdYZdZdZdZedZd S( i(t ElementTreecCs||jddS(Nt}i(tfind(ttag((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyt_ns st XmlDictObjectcBs\eZdZddZdZdZdZedZ edZ dZ RS( sD Adds object like functionality to the standard dictionary. cCs)|dkri}ntj||dS(N(tNonetdictt__init__(tselftinitdict((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyRs  cCs |j|S(N(t __getitem__(R titem((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyt __getattr__scCs|j||dS(N(t __setitem__(R R tvalue((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyt __setattr__scCs!d|kr|jdSdSdS(Nt_textt(R (R ((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyt__str__s  cCs`t|tr)td|jDSt|trXg|D]}tj|^q?S|SdS(sT Static method to wrap a dictionary recursively as an XmlDictObject css*|] \}}|tj|fVqdS(N(Rtwrap(t.0tktv((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pys *sN(t isinstanceRRtitemstlistR(txR((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyR#s  cCs`t|tr)td|jDSt|trXg|D]}tj|^q?S|SdS(Ncss*|] \}}|tj|fVqdS(N(Rt_un_wrap(RRR((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pys 4s(RRRRRR(RR((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyR0s  cCs tj|S(sp Recursively converts an XmlDictObject to a standard dictionary and returns the result. (RR(R ((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pytun_wrap:sN( t__name__t __module__t__doc__RRR RRt staticmethodRRR(((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyRs      cCst|tstt|trx|jD]\}}t|dkrat||_q1t|trxc|D]/}tj|}|j |t ||qwWq1tj|}|j |t ||q1Wnt||_dS(NR( RRtAssertionErrorRtstrttextRRtElementtappendt_convert_dict_to_xml_recurse(tparenttdictitemRtchildt listchildtelem((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyR'Bs   cCs:t|jd}tj|}t||||S(s= Converts a dictionary to an XML ElementTree Element i(RtkeysRR%R'(txmldicttroottagtroot((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pytconvert_dict_to_xmlWscCs|}tt|jdkrd|krY|djtt|jqi|d<|djtt|jnx|D]}t||}t|j|krt|t|jtr|t|jj |q/|t|j|g|t|js  4  -external/__init__.pyo000064400000000220147576505410010666 0ustar00 -P`c@sdS(N((((s9/usr/lib/python2.7/site-packages/lsm/external/__init__.pytsexternal/xmltodict.pyo000064400000011601147576505410011143 0ustar00 -P`c@sZddlmZdZdefdYZdZdZdZedZd S( i(t ElementTreecCs||jddS(Nt}i(tfind(ttag((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyt_ns st XmlDictObjectcBs\eZdZddZdZdZdZedZ edZ dZ RS( sD Adds object like functionality to the standard dictionary. cCs)|dkri}ntj||dS(N(tNonetdictt__init__(tselftinitdict((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyRs  cCs |j|S(N(t __getitem__(R titem((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyt __getattr__scCs|j||dS(N(t __setitem__(R R tvalue((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyt __setattr__scCs!d|kr|jdSdSdS(Nt_textt(R (R ((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyt__str__s  cCs`t|tr)td|jDSt|trXg|D]}tj|^q?S|SdS(sT Static method to wrap a dictionary recursively as an XmlDictObject css*|] \}}|tj|fVqdS(N(Rtwrap(t.0tktv((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pys *sN(t isinstanceRRtitemstlistR(txR((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyR#s  cCs`t|tr)td|jDSt|trXg|D]}tj|^q?S|SdS(Ncss*|] \}}|tj|fVqdS(N(Rt_un_wrap(RRR((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pys 4s(RRRRRR(RR((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyR0s  cCs tj|S(sp Recursively converts an XmlDictObject to a standard dictionary and returns the result. (RR(R ((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pytun_wrap:sN( t__name__t __module__t__doc__RRR RRt staticmethodRRR(((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyRs      cCst|trx|jD]\}}t|dkrLt||_qt|trxc|D]/}tj|}|j|t ||qbWqtj|}|j|t ||qWnt||_dS(NR( RRRtstrttextRRtElementtappendt_convert_dict_to_xml_recurse(tparenttdictitemRtchildt listchildtelem((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pyR&Bs   cCs:t|jd}tj|}t||||S(s= Converts a dictionary to an XML ElementTree Element i(RtkeysRR$R&(txmldicttroottagtroot((s:/usr/lib/python2.7/site-packages/lsm/external/xmltodict.pytconvert_dict_to_xmlWscCs|}tt|jdkrd|krY|djtt|jqi|d<|djtt|jnx|D]}t||}t|j|krt|t|jtr|t|jj |q/|t|j|g|t|js  4  -_data.pyo000064400000103375147576505410006374 0ustar00 -P`c@sddlmZddlZddlZddlmZyddlZWne k rgddlZnXddl m Z ddl m Z mZmZmZddlZdejfdYZdejfd YZd eeefd YZed d dedd dedd dedd dedd dedd dedd dedd ddefdYZejdZed d dedd d ed!d d"edd d#edd d$ed%d d&edd ded'd d(edd dd)efd*YZed d dedd d+edd d,ed-d d.edd dd/efd0YZed d dedd d1ed2d d3ed4d d5edd ded-d d6edd dedd d7ed8d d9ed:d d;d<efd=YZed d dedd d>ed2d d3ed4d d?ed'd d@edd dAedd ddBefdCYZed d dedd dDedEd dFedd ddGefdHYZed d dedId dJedKd dLedMd dNedOd dPedQd dRedSd dTedUd dVedWd dXedYd dZedd d[d\efd]YZed^d d_ed`d daedbd d$dcefddYZ ed d deedd dfedgd dhedid djedd dedd d[dkefdlYZ!ed d deedmd dnedod dpedqd dredsd dtedud dvedd dedd d[dwefdxYZ"dyefdzYZ#ed d dedd d ed{d d|edd d}edd dedd dd~efdYZ$e%dkrndS(i(tABCMetaN(twith_metaclass(t WHITESPACE(t get_classtdefault_propertyt ErrorNumbertLsmErrort DataEncodercBseZdZdZRS(s? Custom json encoder for objects derived form ILsmData cCs<t|ts.tdtt|n |jSdS(Nsincorrect class type:(t isinstancetIDatat ValueErrortstrttypet_to_dict(tselftmy_class((s-/usr/lib/python2.7/site-packages/lsm/_data.pytdefault*s(t__name__t __module__t__doc__R(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR%st DataDecodercBsJeZdZedZedZedZejdZ RS(s? Custom json decoder for objects derived from ILsmData cCsXi}d|kr$tj|}n0x-|jD]\}}tj|||tj|S|SdS(s) Decodes the parsed json N(R R"RR#RR!(te((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt__decodeTs   cCstjtj|S(N(RRtjsontloads(Rt json_stringt_w((s-/usr/lib/python2.7/site-packages/lsm/_data.pytdecode`s( RRRt staticmethodR#R!RRtmatchR.(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR1s  R cBs/eZdZdZedZdZRS(s? Base class functionality of serializable classes. cCsqi|jjd6}xWt|jjD]@\}}t|tr[|j||d(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt size_bytesscCs+|jdkr$ttjdn|jS(s String. SCSI VPD83 ID. New in version 1.3. Only available for DAS(direct attached storage) systems. The VPD83 ID could be used in 'lsm.SCSI.disk_paths_of_vpd83()' when physical disk is exposed to OS directly. RCs5Disk.vpd83 is not supported by current disk or plugin(RORRt NO_SUPPORT(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pytvpd83s  cCs+|jdkr$ttjdn|jS(sP String. Disk location in storage topology. New in version 1.3. RCs:Disk.location property is not supported by this plugin yet(RPRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pytlocation&s  cCs.|jtjkr'ttjdn|jS(s Integer. New in version 1.3. Disk rotation speed - revolutions per minute(RPM): -1 (LSM_DISK_RPM_UNKNOWN): Unknown RPM 0 (LSM_DISK_RPM_NON_ROTATING_MEDIUM): Non-rotating medium (e.g., SSD) 1 (LSM_DISK_RPM_ROTATING_UNKNOWN_SPEED): Rotational disk with unknown speed >1: Normal rotational disk (e.g., HDD) s,Disk.rpm is not supported by this plugin yet(RQRBtRPM_NO_SUPPORTRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pytrpm1s  cCs.|jtjkr'ttjdn|jS(s Integer. New in version 1.3. Link type, possible values are: lsm.Disk.LINK_TYPE_UNKNOWN Failed to detect link type lsm.Disk.LINK_TYPE_FC Fibre Channel lsm.Disk.LINK_TYPE_SSA Serial Storage Architecture, Old IBM tech. lsm.Disk.LINK_TYPE_SBP Serial Bus Protocol, used by IEEE 1394. lsm.Disk.LINK_TYPE_SRP SCSI RDMA Protocol lsm.Disk.LINK_TYPE_ISCSI Internet Small Computer System Interface lsm.Disk.LINK_TYPE_SAS Serial Attached SCSI lsm.Disk.LINK_TYPE_ADT Automation/Drive Interface Transport Protocol, often used by Tape. lsm.Disk.LINK_TYPE_ATA PATA/IDE or SATA. lsm.Disk.LINK_TYPE_USB USB disk. lsm.Disk.LINK_TYPE_SOP SCSI over PCI-E lsm.Disk.LINK_TYPE_PCIE PCI-E, e.g. NVMe s2Disk.link_type is not supported by this plugin yet(RRRBtLINK_TYPE_NO_SUPPORTRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt link_typeDs  cCs|jS(N(R;(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR8isiiiiii i@iiiiiii iiiiii i@N(GRRRtSUPPORTED_SEARCH_KEYStBLOCK_COUNT_NOT_FOUNDtBLOCK_SIZE_NOT_FOUNDt TYPE_UNKNOWNt TYPE_OTHERtTYPE_ATAt TYPE_SATAtTYPE_SAStTYPE_FCtTYPE_SOPt TYPE_SCSItTYPE_LUNt TYPE_NL_SAStTYPE_HDDtTYPE_SSDt TYPE_HYBRIDtSTATUS_UNKNOWNt STATUS_OKt STATUS_OTHERtSTATUS_PREDICTIVE_FAILUREt STATUS_ERRORtSTATUS_REMOVEDtSTATUS_STARTINGtSTATUS_STOPPINGtSTATUS_STOPPEDtSTATUS_INITIALIZINGtSTATUS_MAINTENANCE_MODEtSTATUS_SPARE_DISKtSTATUS_RECONSTRUCTt STATUS_FREERXt RPM_UNKNOWNtRPM_NON_ROTATING_MEDIUMtRPM_ROTATING_UNKNOWN_SPEEDRZtLINK_TYPE_UNKNOWNt LINK_TYPE_FCt LINK_TYPE_SSAt LINK_TYPE_SBPt LINK_TYPE_SRPtLINK_TYPE_ISCSIt LINK_TYPE_SASt LINK_TYPE_ADTt LINK_TYPE_ATAt LINK_TYPE_USBt LINK_TYPE_SOPtLINK_TYPE_PCIEtLED_STATUS_UNKNOWNtLED_STATUS_IDENT_ONtLED_STATUS_IDENT_OFFtLED_STATUS_IDENT_UNKNOWNtLED_STATUS_FAULT_ONtLED_STATUS_FAULT_OFFtLED_STATUS_FAULT_UNKNOWNtLINK_SPEED_UNKNOWNtHEALTH_STATUS_UNKNOWNtHEALTH_STATUS_FAILtHEALTH_STATUS_WARNtHEALTH_STATUS_GOODtNoneRStpropertyRTRVRWRYR[R8(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRBs     %s*(?:^6[0-9a-f]{31})|(?:^[235][0-9a-f]{15})$sUser given nameRVs"Vital product page 0x83 identifiersVolume block sizesNumber of blockst admin_states$Enabled or disabled by administratortpool_idsPool identifierRLcBs|eZdZdddgZdZdZdZdZdZdZ d Z dZ dZ d Z d ZdZd Zd ZdZdZdZd Zd Zd ZdZdZdZdZdZdZdZdZd Z d Z!d Z"d Z#d Z$d Z%dZ&dZ'dZ(d Z)dZ*dZ+d Z,dZ-dZ.d Z/dZ0dZ1d Z2dZ3dZ4dZ5ddZ7e8dZ9dZ:e;dZ<RS(s Represents a volume. R9R@Riiiiiiiii iii2i<i3i=iiic Cs||_||_|rAtj| rAttjd|n||_||_||_ ||_ ||_ ||_ | |_ dS(Ns^Incorrect format of VPD 0x83 NAA(3) string: '%s', expecting 32 or 16 lower case hex characters(RDRERLRMRRRNRORGRHt _admin_stateRJt_pool_idRK( RRDRERORGRHRRJRRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs          cCs|j|jS(s' Volume size in bytes. (R=R>(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRTscCs|jS(N(R;(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR8scCs|rtj|rtStS(sI Returns True if string is valid vpd 0x83 representation (t_vol_regex_vpd83R0tTruetFalse(tvpd((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRMsN(=RRRR\tREPLICATE_UNKNOWNtREPLICATE_CLONEtREPLICATE_COPYtREPLICATE_MIRROR_SYNCtREPLICATE_MIRROR_ASYNCtPROVISION_UNKNOWNtPROVISION_THINtPROVISION_FULLtPROVISION_DEFAULTtADMIN_STATE_DISABLEDtADMIN_STATE_ENABLEDtRAID_TYPE_UNKNOWNtRAID_TYPE_RAID0tRAID_TYPE_RAID1tRAID_TYPE_RAID3tRAID_TYPE_RAID4tRAID_TYPE_RAID5tRAID_TYPE_RAID6tRAID_TYPE_RAID10tRAID_TYPE_RAID15tRAID_TYPE_RAID16tRAID_TYPE_RAID50tRAID_TYPE_RAID60tRAID_TYPE_RAID51tRAID_TYPE_RAID61tRAID_TYPE_JBODtRAID_TYPE_MIXEDtRAID_TYPE_OTHERtSTRIP_SIZE_UNKNOWNtDISK_COUNT_UNKNOWNtMIN_IO_SIZE_UNKNOWNtOPT_IO_SIZE_UNKNOWNtVCR_STRIP_SIZE_DEFAULTtWRITE_CACHE_POLICY_UNKNOWNtWRITE_CACHE_POLICY_WRITE_BACKtWRITE_CACHE_POLICY_AUTOt WRITE_CACHE_POLICY_WRITE_THROUGHtWRITE_CACHE_STATUS_UNKNOWNtWRITE_CACHE_STATUS_WRITE_BACKt WRITE_CACHE_STATUS_WRITE_THROUGHtREAD_CACHE_POLICY_UNKNOWNtREAD_CACHE_POLICY_ENABLEDtREAD_CACHE_POLICY_DISABLEDtREAD_CACHE_STATUS_UNKNOWNtREAD_CACHE_STATUS_ENABLEDtREAD_CACHE_STATUS_DISABLEDtPHYSICAL_DISK_CACHE_UNKNOWNtPHYSICAL_DISK_CACHE_ENABLEDtPHYSICAL_DISK_CACHE_DISABLEDt$PHYSICAL_DISK_CACHE_USE_DISK_SETTINGRRSRRTR8R/RM(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRLrsp   sUser defined system namesEnumerated status of systemt status_infos#Detail status information of systemtSystemcBseZd ZdZdZdZdZdZdZdZ dZ dZ dZ dZ ddddd Zed Zed Zed ZRS(iiiiiiiiRCc Cs||_||_||_||_||_||_|dkrQtj|_ n ||_ |dkrutj |_ n ||_ dS(N( RDRERIt _status_infoRKt _fw_versionRRtREAD_CACHE_PCT_NO_SUPPORTt_read_cache_pcttMODE_NO_SUPPORTt_mode( RRDRERIRRKRRR((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRS s         cCs+|jdkr$ttjdn|jS(s String. Firmware version string. New in version 1.3. On some system, it might contain multiple version strings, example: "Package: 23.32.0-0009, FW: 3.440.05-3712" RCs7System.fw_version() is not supported by this plugin yet(RRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt fw_versions  cCs.|jtjkr'ttjdn|jS(sQ Integer(enumerated value). System mode. New in version 1.3. Only available for HW RAID systems at this time. Possible values: * lsm.System.MODE_HARDWARE_RAID The logical volume(aka, RAIDed virtual disk) can be exposed to OS while hardware RAID card is handling the RAID algorithm. Physical disk can not be exposed to OS directly. * lsm.System.MODE_HBA The physical disks can be exposed to OS directly. SCSI enclosure service might be exposed to OS also. s/System.mode is not supported by this plugin yet(RRRRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pytmode)s  cCs.|jtjkr'ttjdn|jS(s Integer. Read cache percentage. New in version 1.3. Possible values: * 0-100 The read cache percentage. The write cache percentage will then be 100 - read_cache_pct s9System.read_cache_pct is not supported by this plugin yet(RRRRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pytread_cache_pct=s   iiiiii N(RRRlRmRptSTATUS_DEGRADEDRoRnRt MODE_UNKNOWNtMODE_HARDWARE_RAIDtMODE_HBARtREAD_CACHE_PCT_UNKNOWNRRSRRRR(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRs" sUser supplied namet total_spacesTotal space in bytest free_spacesFree space in bytessText explaining statussPlug-in private datat element_typesWhat pool can be used fortunsupported_actionss"What cannot be done with this pooltPoolcBseZdZddgZdZdZdZdZdZdZ dZ dZ dZ dZ dZdZdZdZdZdZd Zd!Zd"Zd#Zd$Zd ZdZdZdZd%dZRS(&s# Pool specific information R9R@iiiiiiii ii i i iic Cs^||_||_||_||_||_||_||_||_| |_| |_ dS(N( RDREt _element_typet_unsupported_actionst _total_spacet _free_spaceRIRRJRK( RRDRERRRRRIRRJRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs         iiiii i@iiiiiiii iii i@iN(RRRR\tTOTAL_SPACE_NOT_FOUNDtFREE_SPACE_NOT_FOUNDtELEMENT_TYPE_POOLtELEMENT_TYPE_VOLUMEtELEMENT_TYPE_FStELEMENT_TYPE_DELTAtELEMENT_TYPE_VOLUME_FULLtELEMENT_TYPE_VOLUME_THINtELEMENT_TYPE_SYS_RESERVEDtUNSUPPORTED_VOLUME_GROWtUNSUPPORTED_VOLUME_SHRINKRlRmRnRRpRttSTATUS_RECONSTRUCTINGtSTATUS_VERIFYINGRutSTATUS_GROWINGtMEMBER_TYPE_UNKNOWNtMEMBER_TYPE_OTHERtMEMBER_TYPE_DISKtMEMBER_TYPE_POOLRRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRMs8 sFile system namesFree space availables$What pool the file system resides ons System IDt FileSystemcBs#eZdddgZddZRS(R9R@RcCsC||_||_||_||_||_||_||_dS(N(RDRERRRRJRK(RRDRERRRRJRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs      N(RRR\RRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRss Snapshot namettss#Time stamp the snapshot was createdt FsSnapshotcBseZddZRS(cCs.||_||_t||_||_dS(N(RDREtintt_tsRK(RRDRERRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs  N(RRRRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRstfs_idsFilesystem that is exportedt export_paths Export pathtauthsAuthentication typetroots!List of hosts with no_root_squashtrws*List of hosts with Read & Write privilegestros'List of hosts with Read only privilegestanonuidsUID for anonymous user idtanongidsGID for anonymous group idtoptionss"String containing advanced optionssPlugin private datat NfsExportcBs,eZddgZdZdZddZRS(R9Riic Csg||_||_||_||_||_||_||_||_| |_| |_ | |_ dS(N( RDt_fs_idt _export_patht_autht_roott_rwt_rot_anonuidt_anongidt_optionsRK( RRDR R R RRRRRRRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs          N(RRR\tANON_UID_GID_NAtANON_UID_GID_ERRORRRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR s t src_blocksSource logical block addresst dest_blocks!Destination logical block addresst block_countt BlockRangecBseZdZRS(cCs||_||_||_dS(N(t _src_blockt _dest_blockt _block_count(RRRR((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs  (RRRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRssUnique instance identifiersAccess group nametinit_idssList of initiator IDst init_typesInitiator typet AccessGroupcBseZddgZdZdZdZdZdZd dZ e dZ e j d e jZe d ed Ze ed ZRS( R9R@iiiiicCsC||_||_tj||_||_||_||_dS(N(RDRERt_standardize_init_listt _init_idst _init_typeRJRK(RRDRER!R"RJRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs     cCs_g}xR|D]J}tj|\}}}|rA|j|q ttjd|q W|S(NsInvalid initiator ID %s(Rtinitiator_id_verifyR RRRN(RRtitvalidRtinit_id((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR s  sR ^(0x|0X)?([0-9A-Fa-f]{2}) (([\.:\-])?[0-9A-Fa-f]{2}){7}$ cCs|jds-|jds-|jdr[|dksH|tjkr[ttj|fSntjjt|r|dks|tjkrttjtj |fSn|rt t j d|nt ddfS(s Public method which can be used to verify an initiator id :param init_id: :param init_type: :param raise_exception: Will throw a LsmError INVALID_ARGUMENT if not a valid initiator address :return:(Bool, init_type, init_id) Note: init_id will be returned in normalized format if it's a WWPN tiqnteuitnaasInitiator id '%s' is invalidN(t startswithRRtINIT_TYPE_ISCSI_IQNRt _regex_wwpnR0R tINIT_TYPE_WWPNt_wwpn_to_lsm_typeRRRNR(R&Rtraise_exception((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR#s     cCstjjt|ryt|}|j}tjdd|}tjdd|}djtjd|}|S|rt t j d|ndS(s Convert provided WWPN string into LSM standard one: LSM WWPN format: ^(?:[0-9a-f]{2}:){7}[0-9a-f]{2}$ LSM WWPN Example: 10:00:00:00:c9:95:2f:de Acceptable WWPN format is: ^[0x|0X]{0,1}(:?[0-9A-Fa-f]{2}[\.\-:]{0,1}){7}[0-9A-Fa-f]{2}$ Acceptable WWPN example: 10:00:00:00:c9:95:2f:de 10:00:00:00:C9:95:2F:DE 10-00-00-00-C9-95-2F-DE 10-00-00-00-c9-95-2f-de 10.00.00.00.C9.95.2F.DE 10.00.00.00.c9.95.2f.de 0x10000000c9952fde 0X10000000C9952FDE 10000000c9952fde 10000000C9952FDE Return the LSM WWPN Return None if raise_error is False and not a valid WWPN. t0xRCs [^0-9a-f]t:s..sInvalid WWPN Initiator: %sN( RR,R0R tlowertretsubtjointfindallRRRNR(twwpnt raise_errorts((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR.+s   N(RRR\tINIT_TYPE_UNKNOWNtINIT_TYPE_OTHERR-R+tINIT_TYPE_ISCSI_WWPN_MIXEDRRSR/R R3tcompiletXR,RR#RR.(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRs   t port_typesTarget port typetservice_addresssTarget port service addresstnetwork_addresssTarget port network addresstphysical_addresssTarget port physical addresst physical_namesTarget port physical port namet TargetPortcBs8eZddgZdZdZdZdZddZRS(R9R@iiiic CsL||_||_||_||_||_||_||_||_dS(N(RDt _port_typet_service_addresst_network_addresst_physical_addresst_physical_nameRJRK( RRDRERFRGRHRIRJRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSbs       N( RRR\R`Rdt TYPE_FCOEt TYPE_ISCSIRRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRDRs  t CapabilitiescBs]eZdZdZdZdZdZdZdZdZ dZ dZ d Z d Z d Zd Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"d Z#d!Z$d"Z%d#Z&d$Z'd%Z(d&Z)d'Z*d(Z+d)Z,d*Z-d+Z.d,Z/d-Z0d.Z1d/Z2d0Z3d1Z4d2Z5d3Z6d4Z7d5Z8d6Z9d7Z:d8Z;d9Z<d:Z=d;Z>d<Z?d=Z@d>ZAd?ZBd@ZCdAZDdBZEdCZFdDZGdEZHdFZIdGZJdHZKdIZLdJZMdKZNdLZOdMZPdNZQdOZRdPZSdQZTdRZUdSZVdTZWd\dUZYdVZZdWZ[e\dXZ]e^dYZ_edZZ`d[ZaRS(]iiiiiiiiiiiiiiii!i"i#i$i%i&i'i(i)i*i+i,i-i.i/i0i5i6i7i8i9i:i;i<i=i>i?i@iAiBidieifigihiiijikiminioipiqirixiyizi{i|iiiiiiiiiiiiiiiiiiiicCs;i|jjd6djg|jD]}d|^q d6S(NRRCs%02xtcap(R1RR5t_cap(Rtb((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR scCs=|dk r'ttj||_nttj|_dS(N(Rt bytearraytbinasciit unhexlifyRNRLt_NUM(RRN((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs cCs|j|tjkS(N(tgetRLt SUPPORTED(Rt capability((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt supportedscCs'|t|jkrtjS|j|S(N(tlenRNRLt UNSUPPORTED(RRV((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRTscCst}xttjjD]o\}}t|tjrt|t kr|ddkrtj |ko|tj knr||| string name iR4( R"RRLR2RRtsixt string_typesR Rt_CAP_NUM_BEGINRS(tlsm_cap_to_str_convtc_strtc_int((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt_lsm_cap_to_str_dicts "$"cCsstj}|r|Si}xPt|jD]<}|j|tjkr/||krk||||s   "  31+.{"R  1<( 4%j+*% _common.pyo000064400000042405147576505410006747 0ustar00 -P`c@sddlZddlZddlZddlZddlZddlZyddlmZWn!ek rddl mZnXddl Z y*ddl m Z m Z ddlmZWn7ek rddlm Z m Z ddlmZnXddlZddlZddlZddlZddlZeddZdZdefdYZd ZeZid d 6dRd6dSd6dTd6dUd6dVd6dWd6dXd6dYd6dZd6d[d6d\d6d]d6d^d 6d_d"6d`d#6dad$6dbd&6dcd(6ddd)6ded*6dfd,6dgd.6dhd/6did06Zd,d&d dddgZe d1Z!d2Z"d3Z#ddd4Z$d5Z%d6Z&d7Z'd8Z(d9Z)d:Z*d;Z+d<e,fd=YZ-ed>d?d@edAd?dBedCd?dDdEe,fdFYZ.dddGZ/dHZ0dIefdJYZ1dKefdLYZ2dMZ3dNZ4dOej5fdPYZ6e7dQkrej8ndS(jiN(tSequence(tURLErrort HTTPError(turlparsecs_dfd}fd}t||r:|ndd|fd}|S(s Creates the get/set properties for the given name. It assumes that the actual attribute is '_' + name TODO: Expand this with domain validation to ensure the values are correct. t_cs t|S(N(tgetattr(tself(tattribute_name(s//usr/lib/python2.7/site-packages/lsm/_common.pytgetter9scst||dS(N(tsetattr(Rtvalue(R(s//usr/lib/python2.7/site-packages/lsm/_common.pytsetter<scst||S(N(R (tcls(tnametprop(s//usr/lib/python2.7/site-packages/lsm/_common.pyt decoratorAsN(tpropertytNone(R t allow_settdocRR R((RR Rs//usr/lib/python2.7/site-packages/lsm/_common.pytdefault_property0s  !cCst|tr*ttjt|nt|trt|}d|krd|krrttjdnd|krttjdqnt dt j ttj |nyAt jrt|t jrttj dt|qnWntk rnXtjrGt|trGttjt|nt|tj rtttjt|nt j }t d|ttjd tt||dS( Ns urlopen errors Errno 111sConnection refuseds Errno 113s Host is downsUnexpected network error: sSSL Certificate error (%s)sUnexpected exception: sUnexpected exception (TYPE= %s)(t isinstanceRtLsmErrort ErrorNumbertPLUGIN_AUTH_FAILEDtstrRtNETWORK_CONNREFUSEDtNETWORK_HOSTDOWNterrort tracebackt format_exct NETWORK_ERRORtssltCertificateErrortAttributeErrortsixtPY3tConnectionErrortsockett PLUGIN_BUGttype(texptdesct stack_trace((s//usr/lib/python2.7/site-packages/lsm/_common.pytcommon_urllib2_error_handlerHs:            tProxycBs,eZdZddZdZdZRS(sQ Used to provide an unambiguous error when a feature is not implemented. cCs ||_dS(s< Constructor which takes an object to wrap. N(t proxied_obj(Rtobj((s//usr/lib/python2.7/site-packages/lsm/_common.pyt__init__{scCs;t|j|r%tj|j|SttjddS(sJ Called each time an attribute is requested of the object sUnsupported operationN(thasattrR.t functoolstpartialt_presentRRt NO_SUPPORT(RR ((s//usr/lib/python2.7/site-packages/lsm/_common.pyt __getattr__s cOst|j|||S(sQ Method which is called to invoke the actual method of interest. (RR.(Rt_proxy_method_nametargstkwargs((s//usr/lib/python2.7/site-packages/lsm/_common.pyR4sN(t__name__t __module__t__doc__RR0R6R4(((s//usr/lib/python2.7/site-packages/lsm/_common.pyR-ss s/var/run/lsm/ipcitBii tKiBitKBtKtkitMiBitMBtMtmitGiBi tGBtGtgi(tTiBi tTBtTtti2tPiBitPBtPtpi<tEiBitEBtEtecCspd}|rhx<tD]4}|t|kr|tt|:}|}PqqW|sZd}nd||fS|SdS(s  Convert size in bytes to human readable size The return string will follow IEC binary prefixes, e.g. '1.9 KiB' For size less than 1024, we do nothing but return the int we get. TODO: Need a expect to handle when size is not a int. int() might do. R=s%.2f %sN(RtSIZE_CONS_CHK_LSTt SIZE_CONStfloat(tsizethumantunitstkey_name((s//usr/lib/python2.7/site-packages/lsm/_common.pytshs  cCs t|tS(s Convert integer size in bytes to human readable size. We are following rules of IEC binary prefixes on size: http://en.wikipedia.org/wiki/Gibibyte The biggest of unit this function supported is PiB. The precision is 2 which means you will get '1.99 KiB' (R]tTrue(RY((s//usr/lib/python2.7/site-packages/lsm/_common.pytsize_bytes_2_size_humanscCstjdtj}|j|}d}|r|jd}|jd}|s^t|S|j}|jdd}|tkrt|t |}qnt|S(s Convert human readable size string into integer size in bytes. Following rules of IEC binary prefixes on size: http://en.wikipedia.org/wiki/Gibibyte Supported input size_human in these formats: '1.9KiB' # int(1024*1.9) '1 KiB' # 2**10 '1B' # 1 '2K' # 2*(2**10), treated as '2KiB' '2k' # 2*(2**10), treated as '2KiB' '2KB' # 2*(10**3) s ^ ([0-9\.]+) # 1: number [ \t]* # might have space between number and unit ([a-zA-Z]*) # 2: units $ iiitIBtiB( tretcompiletXtmatchtgrouptinttuppertreplaceRWRX(t size_humantregex_size_humant regex_matcht size_bytestnumberR[((s//usr/lib/python2.7/site-packages/lsm/_common.pytsize_human_2_size_bytess    cCsiy3i}t|}|jr.|j|d|jdD]-}t|rtj||d|qqWdS(s If a message includes new lines we will create multiple syslog entries so that the message is readable. Otherwise it isn't very readable. Hopefully we won't be logging much :-) s s: N(Rtlentsyslog(tleveltprgtmsgtl((s//usr/lib/python2.7/site-packages/lsm/_common.pytpost_msgzs cGs0ttjtjjtjdt|dS(Ni( RRtLOG_ERRtosRtbasenametsystargvR(R((s//usr/lib/python2.7/site-packages/lsm/_common.pyRscGs9tr5ttjtjjtjdt |ndS(Ni( t LOG_VERBOSERRtLOG_INFORRRRRR(R((s//usr/lib/python2.7/site-packages/lsm/_common.pytinfost SocketEOFcBseZdZRS(sL Exception class to indicate when we read zero bytes from a socket. (R:R;R<(((s//usr/lib/python2.7/site-packages/lsm/_common.pyRstcodeRs Error codeRs Error messagetdatasOptional error dataRcBseZddZdZRS(cOs2tj|||||_||_||_dS(s, Class represents an error. N(t ExceptionR0t_codet_msgt_data(RRtmessageRR8R9((s//usr/lib/python2.7/site-packages/lsm/_common.pyR0s  cCsVtj|j}|jdk rA|jrAd||j|jfSd||jfSdS(Ns%s: %s Data: %ss%s: %s (Rterror_number_to_strRRRR(Rt error_no_str((s//usr/lib/python2.7/site-packages/lsm/_common.pyt__str__s N(R:R;RR0R(((s//usr/lib/python2.7/site-packages/lsm/_common.pyRs cCs'i|d6|d6|d6|d6|d6S(sC Used for gathering additional information about an error. tdomainRt exceptiontdebugt debug_data((RRRRR((s//usr/lib/python2.7/site-packages/lsm/_common.pytaddl_error_datascCs|jd}dj|d }t|rat|}x?|dD]}t||}qEWntd}t||}|S(sn Given a class name it returns the class, caller will then need to run the constructor to create. t.iit__main__(RRRt __import__R(t class_nametpartstmoduleREtcomp((s//usr/lib/python2.7/site-packages/lsm/_common.pyt get_classs   RcBs"eZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!d Z"d!Z#d"Z$d#Z%d$Z&d%Z'd&Z(d'Z)d(Z*d)Z+d*Z,e-Z.e/d+Z0RS(,iiiii i i i2i4iei}iiiiiiiiiiiiiiiiiiii,i-i3i7i^iiiiiiiicCsIx>ttjjD]'}tj||krd||fSqWd|S(Ns%s(%d)sUNKNOWN_ERROR_NUMBER(%d)(tlistRt_LOCALStkeys(terror_not error_str((s//usr/lib/python2.7/site-packages/lsm/_common.pyRs(1R:R;tOKtLIB_BUGR't JOB_STARTEDtTIMEOUTtDAEMON_NOT_RUNNINGtPERMISSION_DENIEDt NAME_CONFLICTtEXISTS_INITIATORRxtNO_STATE_CHANGERRRt NO_MEMORYR5t IS_MASKEDtHAS_CHILD_DEPENDENCYtNOT_FOUND_ACCESS_GROUPt NOT_FOUND_FSt NOT_FOUND_JOBtNOT_FOUND_POOLtNOT_FOUND_FS_SStNOT_FOUND_VOLUMEtNOT_FOUND_NFS_EXPORTtNOT_FOUND_SYSTEMtNOT_FOUND_DISKt NOT_LICENSEDtNO_SUPPORT_ONLINE_CHANGEtNO_SUPPORT_OFFLINE_CHANGERtPLUGIN_IPC_FAILtPLUGIN_SOCKET_PERMISSIONtPLUGIN_NOT_EXISTtNOT_ENOUGH_SPACEtTRANSPORT_COMMUNICATIONtTRANSPORT_SERIALIZATIONtTRANSPORT_INVALID_ARGtLAST_INIT_IN_ACCESS_GROUPtUNSUPPORTED_SEARCH_KEYtEMPTY_ACCESS_GROUPtPOOL_NOT_READYt DISK_NOT_FREEtlocalsRt staticmethodR(((s//usr/lib/python2.7/site-packages/lsm/_common.pyRsZ t JobStatuscBseZdZdZdZRS(iii(R:R;t INPROGRESStCOMPLETEtERROR(((s//usr/lib/python2.7/site-packages/lsm/_common.pyRsc CsQt|trt|tsCtd|tt|fnt|dkr}xU|D]}t||d|q\WqMxt||D]\}}t|||qWn|t|krM|dk rMt|t j rt|t j rdSt j | st t|| rMtd|t|tt|fqMndS(Ns6%s call is returning a %s, but is expecting a sequenceiis%s call expected: %s got: %s (RRt TypeErrorRR(Rt type_comparetzipRR#t string_typestinspecttisclasst issubclass(t method_nametexp_typetact_valtavR)tact((s//usr/lib/python2.7/site-packages/lsm/_common.pyR s$  csfd}|S(s4 Decorator function that allows us to ensure that we are getting the correct types back from a function/method call. Note: This is normally frowned upon by the python community, but this API needs to be language agnostic, so making sure we have the correct types is quite important. cs%tjfd}|S(Ncs||}tdkrzt|tkrdtdjtt|fntj|n,tdkrtjd|n|S(Nis.%s call expected %d return values, actual = %di(RRR:R(R8R9R(tfuncttypes(s//usr/lib/python2.7/site-packages/lsm/_common.pytinnerHs%(R2twraps(RR(R(Rs//usr/lib/python2.7/site-packages/lsm/_common.pytouterGs!((RR((Rs//usr/lib/python2.7/site-packages/lsm/_common.pytreturn_requires>s t TestCommoncBs#eZdZdZdZRS(cCsdS(N((R((s//usr/lib/python2.7/site-packages/lsm/_common.pytsetUp`sc Cs y tWn)tk r8}|jt|tnXytdddWnGtk r}|j|jdko|jdko|jdknXtddddd}|j|ddko|ddko|ddko|ddko|ddkdS( Ni tMessagetDataRRRRR(Rt assertTrueRRRRRR(RRUted((s//usr/lib/python2.7/site-packages/lsm/_common.pyt test_simplecs $ &cCsdS(N((R((s//usr/lib/python2.7/site-packages/lsm/_common.pyttearDownws(R:R;RRR(((s//usr/lib/python2.7/site-packages/lsm/_common.pyR_s  Riiiiii@Biii@iʚ;i@i@IIIIIIƤ~IIIId II(9RRtunittestRbRRtcollections.abcRt ImportErrort collectionsRt urllib.errorRRt urllib.parseRturllib2R2RR#R R&R^RRR,tobjectR-tUDS_PATHRRWRVtFalseR]R_RoRRwRRRRRRRRRRRRRRRtTestCaseRR:tmain(((s//usr/lib/python2.7/site-packages/lsm/_common.pyts               +)    (1     Q  ! version.pyc000064400000000242147576505410006762 0ustar00 -P`c@s dZdS(s1.8.1N(tVERSION(((s//usr/lib/python2.7/site-packages/lsm/version.pyts_transport.pyc000064400000021770147576505410007501 0ustar00 -P`c@sddlZddlZddlZddlZddlZddlZddlmZmZddlm Z ddl m Z ddl mZdefdYZdZd ejfd YZed krejndS( iN(tLsmErrort ErrorNumber(t SocketEOF(t DataDecoder(t DataEncodert TransPortcBseZdZdZdZdZdZdZedZ dZ dZ d Z d Z dd Zd d ZdZRS(s Provides wire serialization by using json. Loosely conforms to json-rpc, however a length header was added so that we would have the ability to use non sax like json parsers, which are more abundant. s    N(t__name__t __module__t__doc__RRRR R"t staticmethodR/R0R:R=RBRRFRHR>(((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyRs         cCst|}|j}zxk|ddkr|ddkrh|j|d|dd|ddn|j|d|j}qW|j|dWd|jXdS( s) Test echo server for test case. R1tdoneRR2R3t errorcodeterrormsgN(RR=RFRHR0(R tsrvR((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyt_servers   t_TestTransportcBs5eZdZdZdZdZdZRS(cCshtjtjtj\|_|_t|j|_tj dt d|jf|_ |j j dS(NttargetR8( Rt socketpairR#R$tcR Rtclientt threadingtThreadRRtservertstart(R ((s2/usr/lib/python2.7/site-packages/lsm/_transport.pytsetUps !cCs{ddddddg}x\|D]T}|jjd||jj\}}|j|dk|j||kqWdS( Nt0t s s{}:""sSome text messagetDEADBEEFttestid(RWR:R>t assertTrue(R ttcttR@RA((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyt test_simples  cCsd}d}|jjdi|d6|d6|jt|jjy2|jjdi|d6|d6|jjWn?tk r}|j|j|k|j|j|knXdS(NsTest error messageidRRORP(RWR:t assertRaisesRR>RaRCR(R te_msgte_codeR((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyttest_exceptionss! c CsxtdddD]}d|}idd6dd6|d 6}tj|d t}tjt|tj|}|j t|dkx|D]}|j j |qW|j j \}}|j ||kqWdS( Niii txtdripR1idR2R3R4(trangeR5R6R7tstringRRRRRaRVtsendRWR>( R RtpayloadRRtwiretiR@RA((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyt test_slows  cCsL|jjdd|jj\}}|j|dk|jjdS(NRN(RWR:RR>RaRZtjoin(R RIRA((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyttearDowns(RJRKR\RdRhRqRs(((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyRSs   t__main__(R5RRlR%tunittestRXt lsm._commonRRRR t lsm._dataRR<RR7tobjectRRRtTestCaseRSRJtmain(((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyts       > _iplugin.py000064400000041142147576505410006744 0ustar00# Copyright (C) 2011-2013 Red Hat, Inc. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: tasleson from abc import ABCMeta as _ABCMeta from abc import abstractmethod as _abstractmethod from lsm import LsmError, ErrorNumber from six import with_metaclass class IPlugin(with_metaclass(_ABCMeta, object)): """ Plug-in interface that all plug-ins must implement for basic operation. """ @_abstractmethod def plugin_register(self, uri, password, timeout, flags=0): """ Method first called to setup the plug-in (except for plugin_info) This would be the place to make a connection to the array. Returns None on success, else LsmError exception """ pass @_abstractmethod def time_out_set(self, ms, flags=0): """ Sets any time-outs for the plug-in (ms) Returns None on success, else LsmError exception """ pass @_abstractmethod def time_out_get(self, flags=0): """ Retrieves the current time-out Returns time-out in ms, else raise LsmError """ pass @_abstractmethod def plugin_unregister(self, flags=0): """ Called when the client wants to finish up or the socket goes eof. Plug-in should clean up all resources. Note: In the case where the socket goes EOF and the plugin_unregister runs into errors the exception(s) will not be delivered to the client! Returns None on success, else LsmError exception """ pass @_abstractmethod def job_status(self, job_id, flags=0): """ Returns the stats of the given job. Returns a tuple ( status (enumeration), percent_complete, completed item). else LsmError exception. """ pass @_abstractmethod def job_free(self, job_id, flags=0): """ Frees resources for a given job. Returns None on success, else raises an LsmError """ pass @_abstractmethod def capabilities(self, system, flags=0): """ Returns the capabilities for the selected system, raises LsmError """ pass @_abstractmethod def plugin_info(self, flags=0): """ Returns the description and version for plug-in, raises LsmError Note: Make sure plugin can handle this call before plugin_register is called. """ pass @_abstractmethod def pools(self, search_key=None, search_value=None, flags=0): """ Returns an array of pool objects. Pools are used in both block and file system interfaces, thus the reason they are in the base class. Raises LsmError on error """ pass @_abstractmethod def systems(self, flags=0): """ Returns an array of system objects. System information is used to distinguish resources from on storage array to another when the plug=in supports the ability to have more than one array managed by it Raises LsmError on error """ pass class IStorageAreaNetwork(IPlugin): def volumes(self, search_key=None, search_value=None, flags=0): """ Returns an array of volume objects Raises LsmError on error """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_create(self, pool, volume_name, size_bytes, provisioning, flags=0): """ Creates a volume, given a pool, volume name, size and provisioning Returns a tuple (job_id, new volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_delete(self, volume, flags=0): """ Deletes a volume. Returns Job id or None if completed, else raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_resize(self, volume, new_size_bytes, flags=0): """ Re-sizes a volume. Returns a tuple (job_id, re-sized_volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_replicate(self, pool, rep_type, volume_src, name, flags=0): """ Replicates a volume from the specified pool. In this library, to replicate means to create a new volume which is a copy of the source. Returns a tuple (job_id, replicated volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_replicate_range_block_size(self, system, flags=0): """ Returns the number of bytes per block for volume_replicate_range call. Callers of volume_replicate_range need to use this when calculating start and block lengths. Note: bytes per block may not match volume blocksize. Returns bytes per block, Raises LsmError on error """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_replicate_range(self, rep_type, volume_src, volume_dest, ranges, flags=0): """ Replicates a portion of a volume to itself or another volume. The src, dest and number of blocks values change with vendor, call volume_replicate_range_block_size to get block unit size. Returns Job id or None if completed, else raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_enable(self, volume, flags=0): """ Makes a volume available to the host Returns None on success, else raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_disable(self, volume, flags=0): """ Makes a volume unavailable to the host Returns None on success, else raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def iscsi_chap_auth(self, init_id, in_user, in_password, out_user, out_password, flags): """ Register a user/password for the specified initiator for CHAP authentication. in_user & in_password are for inbound CHAP, out_user & out_password are for outbound CHAP. Note: Setting in_user, in_password or out_user, out_password to None will disable authentication. Raises LsmError on error """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_mask(self, access_group, volume, flags=0): """ Allows an access group to access a volume. Returns None on success, else raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_unmask(self, access_group, volume, flags=0): """ Revokes access for an access group for a volume Returns None on success, else raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def access_groups(self, search_key=None, search_value=None, flags=0): """ Returns a list of access groups, raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def access_group_create(self, name, init_id, init_type, system, flags=0): """ Returns a list of access groups, raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def access_group_delete(self, access_group, flags=0): """ Deletes an access group, Raises LsmError on error """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def access_group_initiator_add(self, access_group, init_id, init_type, flags=0): """ Adds an initiator to an access group, Raises LsmError on error """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def access_group_initiator_delete(self, access_group, init_id, init_type, flags=0): """ Deletes an initiator from an access group, Raises LsmError on error """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volumes_accessible_by_access_group(self, access_group, flags=0): """ Returns the list of volumes that access group has access to. Raises LsmError on error """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def access_groups_granted_to_volume(self, volume, flags=0): """ Returns the list of access groups that have access to the specified, Raises LsmError on error """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_child_dependency(self, volume, flags=0): """ Returns True if this volume has other volumes which are dependant on it. Implies that this volume cannot be deleted or possibly modified because it would affect its children. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def volume_child_dependency_rm(self, volume, flags=0): """ If this volume has child dependency, this method call will fully replicate the blocks removing the relationship between them. This should return None (success) if volume_child_dependency would return False. Note: This operation could take a very long time depending on the size of the volume and the number of child dependencies. Returns None if complete else job id, raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def target_ports(self, search_key=None, search_value=None, flags=0): raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") class INetworkAttachedStorage(IPlugin): """ Class the represents Network attached storage (Common NFS/CIFS operations) """ def fs(self, search_key=None, search_value=None, flags=0): """ Returns a list of file systems on the controller. Raises LsmError on errors. """ pass def fs_delete(self, fs, flags=0): """ WARNING: Destructive Deletes a file system and everything it contains Returns None on success, else job id """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def fs_resize(self, fs, new_size_bytes, flags=0): """ Re-size a file system Returns a tuple (job_id, re-sized file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def fs_create(self, pool, name, size_bytes, flags=0): """ Creates a file system given a pool, name and size. Note: size is limited to 2**64 bytes so max size of a single volume at this time is 16 Exabytes Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def fs_clone(self, src_fs, dest_fs_name, snapshot=None, flags=0): """ Creates a thin, point in time read/writable copy of src to dest. Optionally uses snapshot as backing of src_fs Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def fs_file_clone(self, fs, src_file_name, dest_file_name, snapshot=None, flags=0): """ Creates a thinly provisioned clone of src to dest. Note: Source and Destination are required to be on same filesystem Returns Job id or None if completed, else raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def fs_snapshots(self, fs, flags=0): """ Returns a list of snapshots for the supplied file system, Raises LsmError on error """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def fs_snapshot_create(self, fs, snapshot_name, flags=0): """ Snapshot is a point in time read-only copy Create a snapshot on the chosen file system Returns a tuple (job_id, snap shot created) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. Note: Snapshot name may not match what was passed in (depends on array implementation) """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def fs_snapshot_delete(self, fs, snapshot, flags=0): """ Frees the re-sources for the given snapshot on the supplied filesystem. Returns Job id or None if completed, else raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def fs_snapshot_restore(self, fs, snapshot, files, restore_files, all_files=False, flags=0): """ WARNING: Destructive! Reverts a file-system or just the specified files from the snapshot. If a list of files is supplied but the array cannot restore just them then the operation will fail with an LsmError raised. If files == None and all_files = True then all files on the file-system are restored. Restore_file if not None must be the same length as files with each index in each list referring to the associated file. Returns None on success, else job id, LsmError exception on error """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def fs_child_dependency(self, fs, files, flags=0): """ Returns True if the specified filesystem or specified file on this file system has child dependencies. This implies that this filesystem or specified file on this file system cannot be deleted or possibly modified because it would affect its children. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def fs_child_dependency_rm(self, fs, files, flags=0): """ If this filesystem or specified file on this filesystem has child dependency this method will fully replicate the blocks removing the relationship between them. This should return None(success) if fs_child_dependency would return False. Note: This operation could take a very long time depending on the size of the filesystem and the number of child dependencies. Returns Job id or None if completed, else raises LsmError on errors. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") class INfs(INetworkAttachedStorage): def export_auth(self, flags=0): """ Returns the types of authentication that are available for NFS """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def exports(self, search_key=None, search_value=None, flags=0): """ Get a list of all exported file systems on the controller. """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def export_fs(self, fs_id, export_path, root_list, rw_list, ro_list, anon_uid, anon_gid, auth_type, options, flags=0): """ Exports a filesystem as specified in the export """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") def export_remove(self, export, flags=0): """ Removes the specified export """ raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported") _pluginrunner.py000064400000013072147576505410010026 0ustar00# Copyright (C) 2011-2013 Red Hat, Inc. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: tasleson import socket import traceback import sys from lsm import LsmError, error, ErrorNumber from lsm.lsmcli import cmd_line_wrapper import six import errno from lsm._common import SocketEOF as _SocketEOF from lsm._transport import TransPort def search_property(lsm_objs, search_key, search_value): """ This method does not check whether lsm_obj contain requested property. The method caller should do the check. """ if search_key is None: return lsm_objs return list(lsm_obj for lsm_obj in lsm_objs if getattr(lsm_obj, search_key) == search_value) class PluginRunner(object): """ Plug-in side common code which uses the passed in plugin to do meaningful work. """ @staticmethod def _is_number(val): """ Returns True if val is an integer. """ try: int(val) return True except ValueError: return False def __init__(self, plugin, args): self.cmdline = False if len(args) == 2 and PluginRunner._is_number(args[1]): try: fd = int(args[1]) self.tp = TransPort( socket.fromfd(fd, socket.AF_UNIX, socket.SOCK_STREAM)) # At this point we can return errors to the client, so we can # inform the client if the plug-in fails to create itself try: self.plugin = plugin() except Exception as e: ec_info = sys.exc_info() self.tp.send_error(0, -32099, 'Error instantiating plug-in ' + str(e)) raise six.reraise(*ec_info) except Exception: error(traceback.format_exc()) error('Plug-in exiting.') sys.exit(2) else: self.cmdline = True cmd_line_wrapper(plugin) def run(self): # Don't need to invoke this when running stand alone as a cmdline if self.cmdline: return need_shutdown = False msg_id = 0 try: while True: try: # result = None msg = self.tp.read_req() method = msg['method'] msg_id = msg['id'] params = msg['params'] # Check to see if this plug-in implements this operation # if not return the expected error. if hasattr(self.plugin, method): if params is None: result = getattr(self.plugin, method)() else: result = getattr(self.plugin, method)( **msg['params']) else: raise LsmError(ErrorNumber.NO_SUPPORT, "Unsupported operation") self.tp.send_resp(result) if method == 'plugin_register': need_shutdown = True if method == 'plugin_unregister': # This is a graceful plugin_unregister need_shutdown = False self.tp.close() break except ValueError as ve: error(traceback.format_exc()) self.tp.send_error(msg_id, -32700, str(ve)) except AttributeError as ae: error(traceback.format_exc()) self.tp.send_error(msg_id, -32601, str(ae)) except LsmError as lsm_err: self.tp.send_error(msg_id, lsm_err.code, lsm_err.msg, lsm_err.data) except _SocketEOF: # Client went away and didn't meet our expectations for protocol, # this error message should not be seen as it shouldn't be # occurring. if need_shutdown: error('Client went away, exiting plug-in') except socket.error as se: if se.errno == errno.EPIPE: error('Client went away, exiting plug-in') else: error("Unhandled exception in plug-in!\n" + traceback.format_exc()) except Exception: error("Unhandled exception in plug-in!\n" + traceback.format_exc()) try: self.tp.send_error(msg_id, ErrorNumber.PLUGIN_BUG, "Unhandled exception in plug-in", str(traceback.format_exc())) except Exception: pass finally: if need_shutdown: # Client wasn't nice, we will allow plug-in to cleanup self.plugin.plugin_unregister() sys.exit(2) _local_disk.pyo000064400000044310147576505410007560 0ustar00 -P`c@sddlZddlmZmZddlmZmZmZmZm Z m Z m Z m Z m Z mZmZmZmZdZdefdYZdS(iN(tLsmErrort ErrorNumber( t_local_disk_vpd83_searcht_local_disk_vpd83_gett_local_disk_health_status_gett_local_disk_rpm_gett_local_disk_listt_local_disk_link_type_gett_local_disk_ident_led_ont_local_disk_ident_led_offt_local_disk_fault_led_ont_local_disk_fault_led_offt_local_disk_serial_num_gett_local_disk_led_status_gett_local_disk_link_speed_getcCs:||\}}}|tjkr6t||n|S(N(RtOKR(tfunc_reftargtdataterr_noterr_msg((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt_use_c_lib_functionst LocalDiskcBseZedZedZedZedZedZedZedZ edZ edZ ed Z ed Z ed Zed ZRS( cCs tt|S(s lsm.LocalDisk.vpd83_search(vpd83) Version: 1.3 Usage: Find out the disk paths for given SCSI VPD page 0x83 NAA type ID. Considering multipath, certain VPD83 might have multiple disks associated. Parameters: vpd83 (string) The VPD83 NAA type ID. Returns: [disk_path] List of string. Empty list if not disk found. The disk_path string format is '/dev/sd[a-z]+' for SCSI and ATA disks. SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. Capability: N/A No capability required as this is a library level method. (RR(tvpd83((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt vpd83_search(scCs tt|S(sk lsm.LocalDisk.serial_num_get(disk_path) Version: 1.4 Usage: Query the SCSI VPD80 serial number of given disk path. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: serial_num (string) String of VPD80 serial number. Empty string if not supported. The string format regex is: SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb' ErrorNumber.NOT_FOUND_DISK Provided disk is not found. Capability: N/A No capability required as this is a library level method. (RR (t disk_path((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pytserial_num_getEscCs tt|S(s lsm.LocalDisk.vpd83_get(disk_path) Version: 1.3 Usage: Query the SCSI VPD83 NAA ID of given disk path. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: vpd83 (string) String of VPD83 NAA ID. Empty string if not supported. The string format regex is: (?:^6[0-9a-f]{31})|(?:^[235][0-9a-f]{15})$ SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb' ErrorNumber.NOT_FOUND_DISK Provided disk is not found. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt vpd83_getcscCs tt|S(s lsm.LocalDisk.health_status_get(disk_path) Version: 1.5 Usage: Retrieve the health status of given disk path. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: health_status (integer) Disk health status: -1 (lsm.Disk.HEALTH_STATUS_UNKNOWN): Unknown health status 0 (lsm.Disk.HEALTH_STATUS_FAIL): health status indicates failure 1 (lsm.Disk.HEALTH_STATUS_WARN): health status warns of near failure 2 (lsm.Disk.HEALTH_STATUS_GOOD): health status indicates good health SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb' ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Not supported. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pythealth_status_gets%cCs tt|S(sx Version: 1.3 Usage: Query the disk rotation speed - revolutions per minute (RPM) of given disk path. Require permission to open disk path as read-only and non-block, normally it's root or disk group privilege. Parameters: disk_path (string) The disk path, example '/dev/sdb', '/dev/nvme0n1'. Returns: rpm (integer) Disk rotation speed: -1 (lsm.Disk.RPM_UNKNOWN): Unknown RPM 0 (lsm.Disk.RPM_NON_ROTATING_MEDIUM): Non-rotating medium (e.g., SSD) 1 (lsm.Disk.RPM_ROTATING_UNKNOWN_SPEED): Rotational disk with unknown speed >1: Normal rotational disk (e.g., HDD) SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Not supported. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pytrpm_gets'cCs7t\}}}|tjkr3t||n|S(sm Version: 1.3 Usage: Query local disk paths. Currently, only SCSI, ATA and NVMe disks will be included. Parameters: N/A Returns: [disk_path] List of string. Empty list if not disk found. The disk_path string format is '/dev/sd[a-z]+' for SCSI and ATA disks, '/dev/nvme[0-9]+n[0-9]+' for NVMe disks. SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. Capability: N/A No capability required as this is a library level method. (RRRR(t disk_pathsRR((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pytlistscCs tt|S(s Version: 1.3 Usage: Query the disk link type of given disk path. For SATA disks connected to SAS enclosure, will return lsm.Disk.LINK_TYPE_ATA. Require permission to open disk_path(root user or disk group). Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: link_type (integer) Link type, possible values are: lsm.Disk.LINK_TYPE_UNKNOWN Failed to detect link type lsm.Disk.LINK_TYPE_FC Fibre Channel lsm.Disk.LINK_TYPE_SSA Serial Storage Architecture, Old IBM tech. lsm.Disk.LINK_TYPE_SBP Serial Bus Protocol, used by IEEE 1394. lsm.Disk.LINK_TYPE_SRP SCSI RDMA Protocol lsm.Disk.LINK_TYPE_ISCSI Internet Small Computer System Interface lsm.Disk.LINK_TYPE_SAS Serial Attached SCSI lsm.Disk.LINK_TYPE_ADT Automation/Drive Interface Transport Protocol, often used by Tape. lsm.Disk.LINK_TYPE_ATA PATA/IDE or SATA. lsm.Disk.LINK_TYPE_USB USB disk. lsm.Disk.LINK_TYPE_SOP SCSI over PCI-E lsm.Disk.LINK_TYPE_PCIE PCI-E, e.g. NVMe SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED Insufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt link_type_gets9cCs tt|S(s Version: 1.3 Usage: Turn on the identification LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt ident_led_on-scCs tt|S(s Version: 1.3 Usage: Turn off the identification LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR (R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt ident_led_offIscCs tt|S(s Version: 1.3 Usage: Turn on the fault LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR (R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt fault_led_onescCs tt|S(s Version: 1.3 Usage: Turn off the fault LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR (R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt fault_led_offscCs tt|S(s Version: 1.3 Usage: Get LED status for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: led_status (integer, bit map) Could be combination of these values: lsm.Disk.LED_STATUS_UNKNOWN lsm.Disk.LED_STATUS_IDENT_ON lsm.Disk.LED_STATUS_IDENT_OFF lsm.Disk.LED_STATUS_IDENT_UNKNOWN Has identification LED, but status is unknown. If certain disk has no identification LED, 'led_status' should not contain 'lsm.Disk.LED_STATUS_IDENT_ON' or 'lsm.Disk.LED_STATUS_IDENT_OFF' or 'lsm.Disk.LED_STATUS_IDENT_UNKNOWN' lsm.Disk.LED_STATUS_FAULT_ON lsm.Disk.LED_STATUS_FAULT_OFF lsm.Disk.LED_STATUS_FAULT_UNKNOWN Has fault LED, but status is unknown. If certain disk has no fault LED, 'led_status' should not contain 'lsm.Disk.LED_STATUS_FAULT_ON' or 'lsm.Disk.LED_STATUS_FAULT_OFF' or 'lsm.Disk.LED_STATUS_FAULT_UNKNOWN' SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR (R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pytled_status_gets0cCs tt|S(s Version: 1.4 Usage: Get current negotiated logical link speed for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: link_speed Integer for link speed in Mbps. For example, '3.0 Gbps' will get 3000. SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk is not supported yet. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pytlink_speed_gets(t__name__t __module__t staticmethodRRRRRRR R!R"R#R$R%R&(((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyR&s') ;2(tsixtlsmRRt lsm._clibRRRRRRRR R R R R RRtobjectR(((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyts X __init__.pyo000064400000002356147576505410007060 0ustar00 -P`c@sddlmZddlmZmZmZmZmZmZm Z m Z m Z m Z m Z mZddlmZddlmZmZmZmZmZmZmZmZmZmZmZmZddlmZm Z m!Z!m"Z"ddl#m$Z$ddl%m&Z&m'Z'gZ(dS( i(tVERSION( terrortinfotLsmErrort ErrorNumbert JobStatust uri_parsetmd5tProxytsize_bytes_2_size_humantcommon_urllib2_error_handlertsize_human_2_size_bytestint_div(t LocalDisk( tDisktVolumetPooltSystemt FileSystemt FsSnapshott NfsExportt BlockRanget AccessGroupt TargetPortt CapabilitiestBattery(tIPlugintIStorageAreaNetworktINetworkAttachedStoragetINfs(tClient(t PluginRunnertsearch_propertyN()t lsm.versionRt lsm._commonRRRRRRRRR R R R tlsm._local_diskR t lsm._dataRRRRRRRRRRRRt lsm._ipluginRRRRt lsm._clientRtlsm._pluginrunnerRR t__all__(((s0/usr/lib/python2.7/site-packages/lsm/__init__.pytsRR"_client.pyo000064400000167523147576505410006746 0ustar00 -P`c@sddlZddlZddlmZmZmZmZmZmZm Z m Z m Z m Z m Z mZmZmZmZddlmZddlmZddlmZddlmZddlZdZdZd Z d efd YZ!dS( iN(tVolumet NfsExportt CapabilitiestPooltSystemtBatterytDiskt AccessGroupt FileSystemt FsSnapshott uri_parsetLsmErrort ErrorNumbertINetworkAttachedStoraget TargetPort(treturn_requires(tUDS_PATH(t TransPort(tIDatacCs |d=|S(s Used to remove the self key from the dict d. Self is included when calling the function locals() in a class method. tself((td((s//usr/lib/python2.7/site-packages/lsm/_client.pyt _del_self"scCs/|r+||kr+ttjd|ndS(NsUnsupported search_key: '%s'(R R tUNSUPPORTED_SEARCH_KEY(t search_keytsupported_keys((s//usr/lib/python2.7/site-packages/lsm/_client.pyt_check_search_key+s cCsttjddS(Ns`The libStorageMgmt daemon is not running (process name lsmd), try 'service libstoragemgmt start'(R R tDAEMON_NOT_RUNNING(((s//usr/lib/python2.7/site-packages/lsm/_client.pyt_raise_no_daemon3s tClientcBseZdZdIZdJZdKZdLZddZddZe dZ e dZ dMddd Z edMed ZedMed Ze eejdgd ed ZedMedZeeedZeeeeedZedMedZeeedZeejdejdedZeegdMdMedZeegedZ edMedZ!edMedZ"ee#gdMdMedZ$eejde#edZ%eejde#edZ&eejde#edZ'eeedZ(eejdedZ)eejdedZ*edMedZ+edMed Z,ee-gdMdMed!Z.edMed"Z/edMed#Z0ee1gdMdMed$Z2ee1ed%Z3edMed&Z4ee1ed'Z5ee1ed(Z6ee#ged)Z7ee1ged*Z8ee9ed+Z:eejded,Z;ee<gdMdMed-Z=eejded.Z>eejde<ed/Z?eejde<ed0Z@eejde<dMed1ZAeejddMed2ZBeeCged3ZDeejdeCed4ZEeejded5ZFeejdeGed6ZHee9ed7ZIeejded8ZJeejdged9ZKeeLgdMdMed:ZMeeLeLjNeLjNdMdMed;ZOedMed<ZPeeQgdMdMed=ZReeeeeeged>ZSeeeejdgged?ZTeegegged@ZUee#edAZVedMedBZWedMedCZXeeYgdMdMedDZZeeeeeegedEZ[edMedFZ\edMedGZ]edMedHZ^RS(NiiiicCstddS(NsDo not call directly!(t RuntimeError(Rturitplain_text_passwordt timeout_mstflags((s//usr/lib/python2.7/site-packages/lsm/_client.pytplugin_registerQscCs |jjdttdS(s3 Instruct the plug-in to get ready R"N(t_tptrpcRtlocals(RRtpasswordttimeoutR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyt__start[scCstj}tjj|rx~tj|D]j\}}}xX|D]P}tjj||}y!tj|}|j t SWqDt k rqDXqDWq.Wnt S(N( Rt_plugin_uds_pathtostpathtexiststwalktjoint _TransPortt get_sockettclosetTrueR tFalse(tuds_pathtroott sub_folderstfilestfilenametudsts((s//usr/lib/python2.7/site-packages/lsm/_client.pyt_check_daemon_existses    cCs)t}dtjkr%tjd}n|S(Nt LSM_UDS_PATH(t _UDS_PATHR*tenviron(trc((s//usr/lib/python2.7/site-packages/lsm/_client.pyR)ysi0uc Cs||_||_||_tj|_t|dg}|d}d|krp|jd\}}|}ntj j |j||_ tj j |j rt t j|j |_n/tjrttjd|j nt|j||||dS(Ntschemet+sPlug-in %s not found!(t_urit _passwordt_timeoutRR)t _uds_pathR tsplitR*R+R.t plugin_pathR,R/R0R#R;R R tPLUGIN_NOT_EXISTRt_Client__start( RRRR R!tuR@tplugtproto((s//usr/lib/python2.7/site-packages/lsm/_client.pyt__init__s"        cCs|j|dS(s$ Synonym for close. N(R1(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pytplugin_unregisterscCs6|jjdtt|jjd|_dS(sB Does an orderly plugin_unregister of the plug-in RNN(R#R$RR%R1tNone(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR1s t:c Csg}tjstntj}xtj|D]\}}}x}|D]u}tjj||}ttj |} | j dt d|\} } |j d| || f| j qNWq8W|S(s Retrieves all the available plug-ins Return list of strings of available plug-ins with the "descversion" t plugin_infoR!s%s%s%s(RR;RR)R*R-R+R.R/R0R$tdicttappendR1( t field_sepR!R?R4R5R6R7R8R9ttptitv((s//usr/lib/python2.7/site-packages/lsm/_client.pytavailable_pluginss     !cCs|jjdttS(sr Sets any time-outs for the plug-in (ms) Return None on success, else LsmError exception t time_out_set(R#R$RR%(RtmsR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRYscCs|jjdttS(sd Retrieves the current time-out Return time-out in ms, else raise LsmError t time_out_get(R#R$RR%(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR[scCs|jjdttS(s Returns the stats of the given job. Returns a tuple ( status (enumeration), percent_complete, completed item). else LsmError exception. t job_status(R#R$RR%(Rtjob_idR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR\s cCs|jjdttS(ss Frees resources for a given job number. Returns None on success, else raises an LsmError tjob_free(R#R$RR%(RR]R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR^scCs|jjdttS(sv Fetches the capabilities of the array Returns a capability object, see data,py for details. t capabilities(R#R$RR%(RtsystemR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR_scCs|jjdttS(s> Returns a description and version of plug-in RQ(R#R$RR%(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRQ"scCs,t|tj|jjdttS(s Returns an array of pool objects. Pools are used in both block and file system interfaces, thus the reason they are in the base class. tpools(RRtSUPPORTED_SEARCH_KEYSR#R$RR%(RRt search_valueR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRa/scCs|jjdttS(s Returns an array of system objects. System information is used to distinguish resources from on storage array to another when the plug=in supports the ability to have more than one array managed by it tsystems(R#R$RR%(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRd<scCstjddkr@t|ttfsdttjdqdn$t|tsdttjdn|dks||dkrttjdn|jj dt t S(s lsm.Client.system_read_cache_pct_update(self, system, read_pct, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: This method updates the read cache percentage on a system if supported Parameters: system(lsm.System) an lsm.System object. read_pct(int) the desired read cache percentage. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: returns None on success, else raises LsmError on errors. SpecialExceptions: iis&Invalid read_pct, should be an integerids,Invalid read_pct, should be in range 0 - 100tsystem_read_cache_pct_update( tsyst version_infot isinstancetinttlongR R tINVALID_ARGUMENTR#R$RR%(RR`tread_pctR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyReKs      cCs5tj|tjdt|jjdttS(sg Register a user/password for the specified initiator for CHAP authentication. traise_exceptiontiscsi_chap_auth(Rtinitiator_id_verifytINIT_TYPE_ISCSI_IQNR2R#R$RR%(Rtinit_idtin_usert in_passwordtout_usert out_passwordR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRn}s  cCs,t|tj|jjdttS(s4 Returns an array of volume objects tvolumes(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRvscCs|jjdttS(s Creates a volume, given a pool, volume name, size and provisioning returns a tuple (job_id, new volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. t volume_create(R#R$RR%(Rtpoolt volume_namet size_bytest provisioningR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRws cCs|jjdttS(s Re-sizes a volume. Returns a tuple (job_id, re-sized_volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. t volume_resize(R#R$RR%(Rtvolumetnew_size_bytesR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR|s cCs|jjdttS(s Replicates a volume from the specified pool. Returns a tuple (job_id, replicated volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. tvolume_replicate(R#R$RR%(RRxtrep_typet volume_srctnameR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(sB Returns the size of a replicated block in bytes. t!volume_replicate_range_block_size(R#R$RR%(RR`R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(s- Replicates a portion of a volume to itself or another volume. The src, dest and number of blocks values change with vendor, call volume_replicate_range_block_size to get block unit size. Returns Job id or None when completed, else raises LsmError on errors. tvolume_replicate_range(R#R$RR%(RRRt volume_desttrangesR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(sQ Deletes a volume. Returns None on success, else job id t volume_delete(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(sx Makes a volume available to the host returns None on success, else raises LsmError on errors. t volume_enable(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR scCs|jjdttS(sz Makes a volume unavailable to the host returns None on success, else raises LsmError on errors. tvolume_disable(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs,t|tj|jjdttS(s2 Returns an array of disk objects tdisks(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR*scCs|jjdttS(s< Allows an access group to access a volume. t volume_mask(R#R$RR%(Rt access_groupR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR8scCs|jjdttS(sA Revokes access for an access group for a volume t volume_unmask(R#R$RR%(RRR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyREscCs,t|tj|jjdttS(s1 Returns a list of access groups t access_groups(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRRscCs>tj||dtd\}}|jjdttS(ss Creates an access group and add the specified initiator id, init_type and desired access. Rmitaccess_group_create(RRoR2R#R$RR%(RRRqt init_typeR`R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRcscCs|jjdttS(s) Deletes an access group taccess_group_delete(R#R$RR%(RRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRsscCs>tj||dtd\}}|jjdttS(s6 Adds an initiator to an access group Rmitaccess_group_initiator_add(RRoR2R#R$RR%(RRRqRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs8tj|ddtd}|jjdttS(s; Deletes an initiator from an access group Rmitaccess_group_initiator_deleteN(RRoROR2R#R$RR%(RRRqRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs  cCs|jjdttS(sN Returns the list of volumes that access group has access to. t"volumes_accessible_by_access_group(R#R$RR%(RRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(se Returns the list of access groups that have access to the specified volume. taccess_groups_granted_to_volume(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(s Returns True if this volume has other volumes which are dependant on it. Implies that this volume cannot be deleted or possibly modified because it would affect its children. tvolume_child_dependency(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(s If this volume has child dependency, this method call will fully replicate the blocks removing the relationship between them. This should return None (success) if volume_child_dependency would return False. Note: This operation could take a very long time depending on the size of the volume and the number of child dependencies. Returns None if complete else job id, raises LsmError on errors. tvolume_child_dependency_rm(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs,t|tj|jjdttS(sC Returns a list of file systems on the controller. tfs(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(s WARNING: Destructive Deletes a file system and everything it contains Returns None on success, else job id t fs_delete(R#R$RR%(RRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(s Re-size a file system Returns a tuple (job_id, re-sized file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. t fs_resize(R#R$RR%(RRR~R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(s  Creates a file system given a pool, name and size. Note: size is limited to 2**64 bytes Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. t fs_create(R#R$RR%(RRxRRzR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(s# Creates a thin, point in time read/writable copy of src to dest. Optionally uses snapshot as backing of src_fs Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. tfs_clone(R#R$RR%(Rtsrc_fst dest_fs_nametsnapshotR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR&s cCs|jjdttS(s Creates a thinly provisioned clone of src to dest. Note: Source and Destination are required to be on same filesystem and all directories in destination path need to exist. Returns None on success, else job id t fs_file_clone(R#R$RR%(RRt src_file_nametdest_file_nameRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR;s cCs|jjdttS(sO Returns a list of snapshot names for the supplied file system t fs_snapshots(R#R$RR%(RRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRLscCs|jjdttS(s| Snapshot is a point in time read-only copy Create a snapshot on the chosen file system. Returns a tuple (job_id, snapshot) Notes: - Snapshot name may not match what was passed in (depends on array implementation) - Tuple return values are mutually exclusive, when one is None the other must be valid. tfs_snapshot_create(R#R$RR%(RRt snapshot_nameR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRYscCs|jjdttS(s Frees the re-sources for the given snapshot on the supplied filesystem. Returns None on success else job id, LsmError exception on error tfs_snapshot_delete(R#R$RR%(RRRR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRoscCs|jjdttS(s6 WARNING: Destructive! Reverts a file-system or just the specified files from the snapshot. If a list of files is supplied but the array cannot restore just them then the operation will fail with an LsmError raised. If files == None and all_files = True then all files on the file-system are restored. Restore_file if None none must be the same length as files with each index in each list referring to the associated file. Returns None on success, else job id, LsmError exception on error tfs_snapshot_restore(R#R$RR%(RRRR7t restore_filest all_filesR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(s& Returns True if the specified filesystem or specified file on this file system has child dependencies. This implies that this filesystem or specified file on this file system cannot be deleted or possibly modified because it would affect its children. tfs_child_dependency(R#R$RR%(RRR7R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(s If this filesystem or specified file on this filesystem has child dependency this method will fully replicate the blocks removing the relationship between them. This should return None(success) if fs_child_dependency would return False. Note: This operation could take a very long time depending on the size of the filesystem and the number of child dependencies. Returns None if completed, else job id. Raises LsmError on errors. tfs_child_dependency_rm(R#R$RR%(RRR7R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs cCs|jjdttS(sH What types of NFS client authentication are supported. t export_auth(R#R$RR%(RR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs,t|tj|jjdttS(sL Get a list of all exported file systems on the controller. texports(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRsc CsQt|t|t|r5ttjdn|jjdttS(sD Exports a filesystem as specified in the arguments s(Host cannot both in rw_list and ro_list.t export_fs(tsetR R RkR#R$RR%( Rtfs_idt export_patht root_listtrw_listtro_listtanon_uidtanon_gidt auth_typetoptionsR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs   cCs|jjdttS(s. Removes the specified export t export_remove(R#R$RR%(RtexportR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs,t|tj|jjdttS(s0 Returns a list of target ports t target_ports(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(sQuery the RAID information of certain volume. New in version 1.2. Query the RAID type, strip size, extents count, minimum I/O size, optimal I/O size of given volume. This method requires this capability: lsm.Capabilities.VOLUME_RAID_INFO Args: volume (Volume object): Volume to query flags (int): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: [raid_type, strip_size, disk_count, min_io_size, opt_io_size] raid_type (int): RAID Type of requested volume. Could be one of these values: Volume.RAID_TYPE_RAID0 Stripe Volume.RAID_TYPE_RAID1 Two disks Mirror Volume.RAID_TYPE_RAID3 Byte-level striping with dedicated parity Volume.RAID_TYPE_RAID4 Block-level striping with dedicated parity Volume.RAID_TYPE_RAID5 Block-level striping with distributed parity Volume.RAID_TYPE_RAID6 Block-level striping with two distributed parities, aka, RAID-DP Volume.RAID_TYPE_RAID10 Stripe of mirrors Volume.RAID_TYPE_RAID15 Parity of mirrors Volume.RAID_TYPE_RAID16 Dual parity of mirrors Volume.RAID_TYPE_RAID50 Stripe of parities Volume.RAID_TYPE_RAID60 Stripe of dual parities Volume.RAID_TYPE_RAID51 Mirror of parities Volume.RAID_TYPE_RAID61 Mirror of dual parities Volume.RAID_TYPE_JBOD Just bunch of disks, no parity, no striping. Volume.RAID_TYPE_UNKNOWN The plugin failed to detect the volume's RAID type. Volume.RAID_TYPE_MIXED This volume contains multiple RAID settings. Volume.RAID_TYPE_OTHER Vendor specific RAID type strip_size(int): The size of strip on each disk or other storage extent. For RAID1/JBOD, it should be set as sector size. If plugin failed to detect strip size, it should be set as Volume.STRIP_SIZE_UNKNOWN(0). disk_count(int): The count of disks used for assembling the RAID group(s) where this volume allocated from. For any RAID system using the slice of disk, this value indicate how many disk slices are used for the RAID. For example, on LVM RAID, the 'disk_count' here indicate the count of PVs used for certain volume. Another example, on EMC VMAX, the 'disk_count' here indicate how many hyper volumes are used for this volume. For any RAID system using remote LUN for data storing, each remote LUN should be count as a disk. If the plugin failed to detect disk_count, it should be set as Volume.DISK_COUNT_UNKNOWN(0). min_io_size(int): The minimum I/O size, device preferred I/O size for random I/O. Any I/O size not equal to a multiple of this value may get significant speed penalty. Normally it refers to strip size of each disk(extent). If plugin failed to detect min_io_size, it should try these values in the sequence of: logical sector size -> physical sector size -> Volume.MIN_IO_SIZE_UNKNOWN(0). opt_io_size(int): The optimal I/O size, device preferred I/O size for sequential I/O. Normally it refers to RAID group stripe size. If plugin failed to detect opt_io_size, it should be set to Volume.OPT_IO_SIZE_UNKNOWN(0). Raises: LsmError: ErrorNumber.NO_SUPPORT No support. tvolume_raid_info(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyR s[cCs|jjdttS(s? lsm.Client.pool_member_info(self, pool, flags=lsm.Client.FLAG_RSVD) Version: 1.2 Usage: Query the membership information of certain pool: RAID type, member type and member ids. Currently, LibStorageMgmt supports two types of pool: * Sub-pool -- Pool.MEMBER_TYPE_POOL Pool space is allocated from parent pool. Example: * NetApp ONTAP volume * Disk RAID pool -- Pool.MEMBER_TYPE_DISK Pool is a RAID group assembled by disks. Example: * LSI MegaRAID disk group * EMC VNX pool * NetApp ONTAP aggregate Parameters: pool (lsm.Pool object) Pool to query flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: [raid_type, member_type, member_ids] raid_type (int) RAID Type of requested pool. Could be one of these values: Volume.RAID_TYPE_RAID0 Stripe Volume.RAID_TYPE_RAID1 Two disks Mirror Volume.RAID_TYPE_RAID3 Byte-level striping with dedicated parity Volume.RAID_TYPE_RAID4 Block-level striping with dedicated parity Volume.RAID_TYPE_RAID5 Block-level striping with distributed parity Volume.RAID_TYPE_RAID6 Block-level striping with two distributed parities, aka, RAID-DP Volume.RAID_TYPE_RAID10 Stripe of mirrors Volume.RAID_TYPE_RAID15 Parity of mirrors Volume.RAID_TYPE_RAID16 Dual parity of mirrors Volume.RAID_TYPE_RAID50 Stripe of parities Volume.RAID_TYPE_RAID60 Stripe of dual parities Volume.RAID_TYPE_RAID51 Mirror of parities Volume.RAID_TYPE_RAID61 Mirror of dual parities Volume.RAID_TYPE_JBOD Just bunch of disks, no parity, no striping. Volume.RAID_TYPE_UNKNOWN The plugin failed to detect the volume's RAID type. Volume.RAID_TYPE_MIXED This pool contains multiple RAID settings. Volume.RAID_TYPE_OTHER Vendor specific RAID type member_type (int) Could be one of these values: Pool.MEMBER_TYPE_POOL Current pool(also known as sub-pool) is allocated from other pool(parent pool). The 'raid_type' will set to RAID_TYPE_OTHER unless certain RAID system support RAID using space of parent pools. Pool.MEMBER_TYPE_DISK Pool is created from RAID group using whole disks. Pool.MEMBER_TYPE_OTHER Vendor specific RAID member type. Pool.MEMBER_TYPE_UNKNOWN Plugin failed to detect the RAID member type. member_ids (list of strings) When 'member_type' is Pool.MEMBER_TYPE_POOL, the 'member_ids' will contain a list of parent Pool IDs. When 'member_type' is Pool.MEMBER_TYPE_DISK, the 'member_ids' will contain a list of disk IDs. When 'member_type' is Pool.MEMBER_TYPE_OTHER or Pool.MEMBER_TYPE_UNKNOWN, the member_ids should be an empty list. SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_POOL Capability: lsm.Capabilities.POOL_MEMBER_INFO tpool_member_info(R#R$RR%(RRxR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRns`cCs|jjdttS(s lsm.Client.volume_raid_create_cap_get( self, system, flags=lsm.Client.FLAG_RSVD) Version: 1.2 Usage: This method is dedicated to local hardware RAID cards. Query out all supported RAID types and strip sizes which could be used by lsm.Client.volume_raid_create() method. Parameters: system (lsm.System) Instance of lsm.System flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: [raid_types, strip_sizes] raid_types ([int]) List of integer, possible values are: Volume.RAID_TYPE_RAID0 Volume.RAID_TYPE_RAID1 Volume.RAID_TYPE_RAID5 Volume.RAID_TYPE_RAID6 Volume.RAID_TYPE_RAID10 Volume.RAID_TYPE_RAID50 Volume.RAID_TYPE_RAID60 strip_sizes ([int]) List of integer. Stripe size in bytes. SpecialExceptions: LsmError lsm.ErrorNumber.NO_SUPPORT Method not supported. Sample: lsm_client = lsm.Client('sim://') lsm_sys = lsm_client.systems()[0] disks = lsm_client.disks( search_key='system_id', search_value=lsm_sys.id) free_disks = [d for d in disks if d.status == Disk.STATUS_FREE] supported_raid_types, supported_strip_sizes = lsm_client.volume_raid_create_cap_get(lsm_sys) new_vol = lsm_client.volume_raid_create( 'test_volume_raid_create', supported_raid_types[0], free_disks, supported_strip_sizes[0]) Capability: lsm.Capabilities.VOLUME_CREATE_RAID This method is mandatory when volume_raid_create() is supported. tvolume_raid_create_cap_get(R#R$RR%(RR`R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs5c Cst|dkr'ttjdn|tjkr]t|dkr]ttjdn|tjkrt|dkrttjdn|tjkrt|dkrttjdn|tjkrt|dst|dkrttjd qn|tj kr[t|dsCt|d kr[ttjd q[n|tj krt|dst|d krttjd qn|j j dt tS(s lsm.Client.volume_raid_create(self, name, raid_type, disks, strip_size, flags=lsm.Client.FLAG_RSVD) Version: 1.2 Usage: This method is dedicated to local hardware RAID cards. Create a disk RAID pool and allocate entire storage space to new volume using requested volume name. When dealing with RAID10, 50 or 60, the first half part of 'disks' will be located in one bottom layer RAID group. The new volume and new pool will created within the same system of provided disks. This method does not allow duplicate call, when duplicate call was issued, LsmError with ErrorNumber.DISK_NOT_FREE will be raise. User should check disk.status for Disk.STATUS_FREE before invoking this method. Parameters: name (string) The name for new volume. The requested volume name might be ignored due to restriction of hardware RAID vendors. The pool name will be automatically chosen by plugin. raid_type (int) The RAID type for the RAID group, possible values are: Volume.RAID_TYPE_RAID0 Volume.RAID_TYPE_RAID1 Volume.RAID_TYPE_RAID5 Volume.RAID_TYPE_RAID6 Volume.RAID_TYPE_RAID10 Volume.RAID_TYPE_RAID15 Volume.RAID_TYPE_RAID16 Volume.RAID_TYPE_RAID50 Please check volume_raid_create_cap_get() returns to get supported all raid types of current hardware RAID card. disks ([lsm.Disks,]) A list of lsm.Disk objects. Free disks used for new RAID group. strip_size (int) The size in bytes of strip. When setting strip_size to Volume.VCR_STRIP_SIZE_DEFAULT, it allow hardware RAID cards to choose their default value. Please use volume_raid_create_cap_get() method to get all supported strip size of current hardware RAID card. The Volume.VCR_STRIP_SIZE_DEFAULT is always supported when lsm.Capabilities.VOLUME_CREATE_RAID is supported. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: lsm.Volume The lsm.Volume object for newly created volume. SpecialExceptions: LsmError lsm.ErrorNumber.NO_SUPPORT Method not supported or RAID type not supported. lsm.ErrorNumber.DISK_NOT_FREE Disk is not in Disk.STATUS_FREE status. lsm.ErrorNumber.NOT_FOUND_DISK Disk not found lsm.ErrorNumber.INVALID_ARGUMENT 1. Invalid input argument data. 2. Disks are not from the same system. 3. Disks are not from the same enclosure. 4. Invalid strip_size. 5. Disk count are meet the minimum requirement: RAID1: len(disks) == 2 RAID5: len(disks) >= 3 RAID6: len(disks) >= 4 RAID10: len(disks) % 2 == 0 and len(disks) >= 4 RAID50: len(disks) % 2 == 0 and len(disks) >= 6 RAID60: len(disks) % 2 == 0 and len(disks) >= 8 lsm.ErrorNumber.NAME_CONFLICT Requested name is already be used by other volume. Sample: lsm_client = lsm.Client('sim://') disks = lsm_client.disks() free_disks = [d for d in disks if d.status == Disk.STATUS_FREE] new_vol = lsm_client.volume_raid_create( 'raid0_vol1', Volume.RAID_TYPE_RAID0, free_disks) Capability: lsm.Capabilities.VOLUME_CREATE_RAID Indicate current system support volume_raid_create() method. At least one RAID type should be supported. The strip_size == Volume.VCR_STRIP_SIZE_DEFAULT is supported. is.Illegal input disks argument: no disk includedis7Illegal input disks argument: RAID 1 only allow 2 disksis<Illegal input disks argument: RAID 5 require 3 or more disksis<Illegal input disks argument: RAID 6 require 4 or more diskssRIllegal input disks argument: RAID 10 require even disks count and 4 or more disksisRIllegal input disks argument: RAID 50 require even disks count and 6 or more disksisRIllegal input disks argument: RAID 60 require even disks count and 8 or more diskstvolume_raid_create(tlenR R RkRtRAID_TYPE_RAID1tRAID_TYPE_RAID5tRAID_TYPE_RAID6tRAID_TYPE_RAID10tRAID_TYPE_RAID50tRAID_TYPE_RAID60R#R$RR%(RRt raid_typeRt strip_sizeR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs@Y ! ! ! """cCs|jjdttS(sF lsm.Client.volume_ident_led_on(self, volume, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: This method enables the IDENT LED on a volume if supported Parameters: volume (lsm.Volume) An lsm.Volume object. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: returns None on success, else raises LsmError on errors. SpecialExceptions: tvolume_ident_led_on(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs|jjdttS(sK lsm.Client.volume_ident_led_off(self, volume, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: This method disables the IDENT LED on a volume if supported Parameters: volume (lsm.Volume) An lsm.Volume object. flags (int) Optional. Reserved for future use. Should be set as lsm.Client.FLAG_RSVD. Returns: returns None on success, else raises LsmError on errors. SpecialExceptions: tvolume_ident_led_off(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRscCs,t|tj|jjdttS(s~ lsm.Client.batteries(self, search_key=None, search_value=None, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Query batteries. When present, super capacitors will also be included. Parameters: search_key (string, optional) The key name for the search. Valid search keys are stored in lsm.Battery.SUPPORTED_SEARCH_KEYS search_value (string, optional) The value of search_key to match. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: [lsm.Battery] lsm.Battery (object) lsm.Battery.id (string) Unique ID for this cache hardware. lsm.Battery.name (string) Human friendly name, might include physical location, model name and etc. lsm.Battery.type (int) The hardware type of cache. Could be one of these values: lsm.Battery.TYPE_CHEMICAL Chemical battery. lsm.Battery.TYPE_CAPACITOR Supper capacitor. lsm.Battery.TYPE_OTHER Vendor specific battery type. lsm.Battery.TYPE_UNKNOWN Unknown type. lsm.Battery.status (int, bitmap) Could be any combination of these values: lsm.Battery.STATUS_OK Battery is fully charged, health and not in use currently. lsm.Battery.STATUS_DISCHARGING Battery is in use. lsm.Battery.STATUS_CHARGING Battery is charging. lsm.Battery.STATUS_LEARNING Battery is calibrating itself by discharging battery and recharging again. lsm.Battery.STATUS_DEGRADED Battery is in degraded mode, need attention. For example, battery is near end of life. lsm.Battery.STATUS_ERROR Battery is having hardware error or end of life. lsm.Battery.STATUS_OTHER Vendor specific status. lsm.Battery.STATUS_UNKNOWN Unknown. lsm.Battery.system_id (string) The id of system which current battery belong to. SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT Capability: lsm.Capabilities.BATTERIES t batteries(RRRbR#R$RR%(RRRcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRsBcCs|jjdttS(s lsm.Client.volume_cache_info(self, volume, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Query RAM cache setting and status of specified volume on read and write I/O. Parameters: volume (Lsm.Volume) The lsm.Volume instance. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: [int, int, int, int, int] write_cache_policy (int) The write cache policy. Valid values are: * lsm.Volume.WRITE_CACHE_POLICY_WRITE_BACK The storage system will use write back mode if cache hardware found. * lsm.Volume.WRITE_CACHE_POLICY_AUTO The controller will use write back mode when battery/capacitor is in good health, otherwise, write through mode. * lsm.Volume.WRITE_CACHE_POLICY_WRITE_THROUGH The storage system will use write through mode. * lsm.Volume.WRITE_CACHE_POLICY_UNKNOWN Plugin failed to detect this setting. write_cache_status (int) The status of write cache. Valid values are: * lsm.Volume.WRITE_CACHE_STATUS_WRITE_THROUGH * lsm.Volume.WRITE_CACHE_STATUS_WRITE_BACK * lsm.Volume.WRITE_CACHE_STATUS_UNKNOWN read_cache_policy (int) The policy for read cache. Valid values are: * lsm.Volume.READ_CACHE_POLICY_ENABLED Read cache is enabled, when reading I/O on previous unchanged written I/O or read I/O in cache will be returned to I/O initiator immediately without checking backing store(normally disk). * lsm.Volume.READ_CACHE_POLICY_DISABLED Read cache is disabled. * lsm.Volume.READ_CACHE_POLICY_UNKNOWN Plugin failed to detect the read cache policy. read_cache_status (int) The status of read cache. Valid values are: * lsm.Volume.READ_CACHE_STATUS_ENABLED * lsm.Volume.READ_CACHE_STATUS_DISABLED * lsm.Volume.READ_CACHE_STATUS_UNKNOWN physical_disk_cache (int) Whether physical disk's cache is enabled or not. Please be advised, HDD's physical disk ram cache might be not protected by storage system's battery or capacitor on sudden power loss, you could lose data if a power failure occurs during a write process. For SSD's physical disk cache, please check with the vendor of your hardware RAID card and SSD disk. Valid values are: * lsm.Volume.PHYSICAL_DISK_CACHE_ENABLED Physical disk cache enabled. * lsm.Volume.PHYSICAL_DISK_CACHE_DISABLED Physical disk cache disabled. * lsm.Volume.PHYSICAL_DISK_CACHE_USE_DISK_SETTING Physical disk cache is determined by the disk vendor via physical disks' SCSI caching mode page(0x08 page). It is strongly suggested to change this value to lsm.Volume.PHYSICAL_DISK_CACHE_ENABLED or lsm.Volume.PHYSICAL_DISK_CACHE_DISABLED * lsm.Volume.PHYSICAL_DISK_CACHE_UNKNOWN Plugin failed to detect the physical disk status. SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_CACHE_INFO tvolume_cache_info(R#R$RR%(RR}R!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRsRcCsO|tjkr3|tjkr3ttjdn|jjdtt S(s lsm.Client.volume_physical_disk_cache_update(self, volume, pdc, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Change the setting of RAM physical disk cache of specified volume. On some product(like HPE SmartArray), this action will be effective at system level which means that even you are requesting a change on a specified volume, this change will apply to all other volumes on the same controller(system). Parameters: volume (Lsm.Volume) The lsm.Volume instance. pdc (int) lsm.Volume.PHYSICAL_DISK_CACHE_ENABLED Enable physical disk cache. lsm.Volume.PHYSICAL_DISK_CACHE_DISABLED Disable physical disk cache flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: N/A SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT You might also get NO_SUPPORT error when trying to change SSD physical disk cache on MegaRAID. ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_PHYSICAL_DISK_CACHE_SET Allow changing physical disk cache. lsm.Capabilities.VOLUME_PHYSICAL_DISK_CACHE_SET_SYSTEM_LEVEL Indicate that this action will change system settings which are effective on all volumes in this storage system. For example, on HPE SmartArray, the physical disk cache setting is a controller level setting. s`Argument pdc should be Volume.PHYSICAL_DISK_CACHE_ENABLED or Volume.PHYSICAL_DISK_CACHE_DISABLEDt!volume_physical_disk_cache_update( RtPHYSICAL_DISK_CACHE_ENABLEDtPHYSICAL_DISK_CACHE_DISABLEDR R RkR#R$RR%(RR}tpdcR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRhs )   cCs^|tjkrB|tjkrB|tjkrBttjdn|jjdt t S(s lsm.Client.volume_write_cache_policy_update(self, volume, wcp, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Change the RAM write cache policy on specified volume. If lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_IMPACT_READ is supported(e.g. HPE SmartArray), the changes on write cache policy might also impact read cache policy. If lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WB_IMPACT_OTHER is supported(e.g. HPE SmartArray), changing write cache policy to write back mode might impact other volumes in the same system. Parameters: volume (Lsm.Volume) The lsm.Volume instance. wcp (int) Could be one of these value: * lsm.Volume.WRITE_CACHE_POLICY_WRITE_BACK Change to write back mode. * lsm.Volume.WRITE_CACHE_POLICY_AUTO Change to auto mode: use write back mode when battery/capacitor is healthy, otherwise use write through. * lsm.Volume.WRITE_CACHE_POLICY_WRITE_THROUGH Change to write through mode. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: N/A SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WRITE_BACK Allow changing to always mode. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_AUTO Allow changing to auto mode. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WRITE_THROUGH Allow changing to disable mode. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_IMPACT_READ Indicate this action might impact read cache policy. lsm.Capabilities.VOLUME_WRITE_CACHE_POLICY_SET_WB_IMPACT_OTHER Indicate that changing to write back mode might impact other volumes. For example, on HPE SmartArray, changing to write back mode will change all other volumes with auto write cache policy to write back mode. sArgument wcp should be Volume.WRITE_CACHE_POLICY_WRITE_BACK or Volume.WRITE_CACHE_POLICY_AUTO or Volume.WRITE_CACHE_POLICY_WRITE_THROUGHt volume_write_cache_policy_update( RtWRITE_CACHE_POLICY_WRITE_BACKtWRITE_CACHE_POLICY_AUTOt WRITE_CACHE_POLICY_WRITE_THROUGHR R RkR#R$RR%(RR}twcpR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs4   cCsO|tjkr3|tjkr3ttjdn|jjdtt S(s lsm.Client.volume_read_cache_policy_update(self, volume, rcp, flags=lsm.Client.FLAG_RSVD) Version: 1.3 Usage: Change the RAM read cache policy of specified volume. If lsm.Capabilities.VOLUME_READ_CACHE_POLICY_SET_IMPACT_WRITE is supported(like HPE SmartArray), the change on write cache policy might also impact read cache policy. Parameters: volume (Lsm.Volume) The lsm.Volume instance. rcp (int) Could be one of these value: * lsm.Volume.READ_CACHE_POLICY_ENABLED Enable read cache. * lsm.Volume.READ_CACHE_POLICY_DISABLED Disable read cache. flags (int, optional): Reserved for future use. Should be set as lsm.Client.FLAG_RSVD Returns: N/A SpecialExceptions: LsmError ErrorNumber.NO_SUPPORT ErrorNumber.NOT_FOUND_VOLUME Capability: lsm.Capabilities.VOLUME_READ_CACHE_POLICY_SET Allow enabling or disabling read cache policy. lsm.Capabilities.VOLUME_READ_CACHE_POLICY_SET_IMPACT_WRITE Indicate that changing read cache policy might impact write cache policy. For example, on HPE SmartArray, disabling read cache will also change write cache policy to write through. s\Argument rcp should be Volume.READ_CACHE_POLICY_ENABLED or Volume.READ_CACHE_POLICY_DISABLEDtvolume_read_cache_policy_update( RtREAD_CACHE_POLICY_ENABLEDtREAD_CACHE_POLICY_DISABLEDR R RkR#R$RR%(RR}trcpR!((s//usr/lib/python2.7/site-packages/lsm/_client.pyRs &   iiiiN(_t__name__t __module__t FLAG_RSVDt#FLAG_VOLUME_CREATE_USE_SYSTEM_CACHEt%FLAG_VOLUME_CREATE_USE_IO_PASSTHROUGHt'FLAG_VOLUME_CREATE_DISABLE_SYSTEM_CACHEt)FLAG_VOLUME_CREATE_DISABLE_IO_PASSTHROUGHR"RIt staticmethodR;R)RORMt_return_requiresRNR1tsixt string_typesRXRYRiR[t_IDataR\R^RR_RQRRaRRdReRnRRvRwR|RRRRRRRRRRRRRRRRRRtboolRRRRRRRRRR RRRR3RRRRRRtANON_UID_GID_NARRRRRRRRRRRRRRRR(((s//usr/lib/python2.7/site-packages/lsm/_client.pyR@s             1                           ag>    DS 2 > ("R*RftlsmRRRRRRRRRR R R R R Rt lsm._commonRRRR=tlsm._transportRR/t lsm._dataRRRRRRR(((s//usr/lib/python2.7/site-packages/lsm/_client.pyts  d   _transport.py000064400000020246147576505410007333 0ustar00# Copyright (C) 2011-2013 Red Hat, Inc. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: tasleson import json import socket import string import os import unittest import threading from lsm._common import LsmError, ErrorNumber from lsm._common import SocketEOF as _SocketEOF from lsm._data import DataDecoder as _DataDecoder from lsm._data import DataEncoder as _DataEncoder class TransPort(object): """ Provides wire serialization by using json. Loosely conforms to json-rpc, however a length header was added so that we would have the ability to use non sax like json parsers, which are more abundant. = 1) for i in wire: self.c.send(i) reply, msg_id = self.client.read_resp() self.assertTrue(payload == reply) def tearDown(self): self.client.send_req("done", None) resp, msg_id = self.client.read_resp() self.assertTrue(resp is None) self.server.join() if __name__ == "__main__": unittest.main() _local_disk.pyc000064400000044310147576505410007544 0ustar00 -P`c@sddlZddlmZmZddlmZmZmZmZm Z m Z m Z m Z m Z mZmZmZmZdZdefdYZdS(iN(tLsmErrort ErrorNumber( t_local_disk_vpd83_searcht_local_disk_vpd83_gett_local_disk_health_status_gett_local_disk_rpm_gett_local_disk_listt_local_disk_link_type_gett_local_disk_ident_led_ont_local_disk_ident_led_offt_local_disk_fault_led_ont_local_disk_fault_led_offt_local_disk_serial_num_gett_local_disk_led_status_gett_local_disk_link_speed_getcCs:||\}}}|tjkr6t||n|S(N(RtOKR(tfunc_reftargtdataterr_noterr_msg((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt_use_c_lib_functionst LocalDiskcBseZedZedZedZedZedZedZedZ edZ edZ ed Z ed Z ed Zed ZRS( cCs tt|S(s lsm.LocalDisk.vpd83_search(vpd83) Version: 1.3 Usage: Find out the disk paths for given SCSI VPD page 0x83 NAA type ID. Considering multipath, certain VPD83 might have multiple disks associated. Parameters: vpd83 (string) The VPD83 NAA type ID. Returns: [disk_path] List of string. Empty list if not disk found. The disk_path string format is '/dev/sd[a-z]+' for SCSI and ATA disks. SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. Capability: N/A No capability required as this is a library level method. (RR(tvpd83((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt vpd83_search(scCs tt|S(sk lsm.LocalDisk.serial_num_get(disk_path) Version: 1.4 Usage: Query the SCSI VPD80 serial number of given disk path. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: serial_num (string) String of VPD80 serial number. Empty string if not supported. The string format regex is: SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb' ErrorNumber.NOT_FOUND_DISK Provided disk is not found. Capability: N/A No capability required as this is a library level method. (RR (t disk_path((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pytserial_num_getEscCs tt|S(s lsm.LocalDisk.vpd83_get(disk_path) Version: 1.3 Usage: Query the SCSI VPD83 NAA ID of given disk path. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: vpd83 (string) String of VPD83 NAA ID. Empty string if not supported. The string format regex is: (?:^6[0-9a-f]{31})|(?:^[235][0-9a-f]{15})$ SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb' ErrorNumber.NOT_FOUND_DISK Provided disk is not found. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt vpd83_getcscCs tt|S(s lsm.LocalDisk.health_status_get(disk_path) Version: 1.5 Usage: Retrieve the health status of given disk path. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: health_status (integer) Disk health status: -1 (lsm.Disk.HEALTH_STATUS_UNKNOWN): Unknown health status 0 (lsm.Disk.HEALTH_STATUS_FAIL): health status indicates failure 1 (lsm.Disk.HEALTH_STATUS_WARN): health status warns of near failure 2 (lsm.Disk.HEALTH_STATUS_GOOD): health status indicates good health SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb' ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Not supported. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pythealth_status_gets%cCs tt|S(sx Version: 1.3 Usage: Query the disk rotation speed - revolutions per minute (RPM) of given disk path. Require permission to open disk path as read-only and non-block, normally it's root or disk group privilege. Parameters: disk_path (string) The disk path, example '/dev/sdb', '/dev/nvme0n1'. Returns: rpm (integer) Disk rotation speed: -1 (lsm.Disk.RPM_UNKNOWN): Unknown RPM 0 (lsm.Disk.RPM_NON_ROTATING_MEDIUM): Non-rotating medium (e.g., SSD) 1 (lsm.Disk.RPM_ROTATING_UNKNOWN_SPEED): Rotational disk with unknown speed >1: Normal rotational disk (e.g., HDD) SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Not supported. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pytrpm_gets'cCs7t\}}}|tjkr3t||n|S(sm Version: 1.3 Usage: Query local disk paths. Currently, only SCSI, ATA and NVMe disks will be included. Parameters: N/A Returns: [disk_path] List of string. Empty list if not disk found. The disk_path string format is '/dev/sd[a-z]+' for SCSI and ATA disks, '/dev/nvme[0-9]+n[0-9]+' for NVMe disks. SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. Capability: N/A No capability required as this is a library level method. (RRRR(t disk_pathsRR((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pytlistscCs tt|S(s Version: 1.3 Usage: Query the disk link type of given disk path. For SATA disks connected to SAS enclosure, will return lsm.Disk.LINK_TYPE_ATA. Require permission to open disk_path(root user or disk group). Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: link_type (integer) Link type, possible values are: lsm.Disk.LINK_TYPE_UNKNOWN Failed to detect link type lsm.Disk.LINK_TYPE_FC Fibre Channel lsm.Disk.LINK_TYPE_SSA Serial Storage Architecture, Old IBM tech. lsm.Disk.LINK_TYPE_SBP Serial Bus Protocol, used by IEEE 1394. lsm.Disk.LINK_TYPE_SRP SCSI RDMA Protocol lsm.Disk.LINK_TYPE_ISCSI Internet Small Computer System Interface lsm.Disk.LINK_TYPE_SAS Serial Attached SCSI lsm.Disk.LINK_TYPE_ADT Automation/Drive Interface Transport Protocol, often used by Tape. lsm.Disk.LINK_TYPE_ATA PATA/IDE or SATA. lsm.Disk.LINK_TYPE_USB USB disk. lsm.Disk.LINK_TYPE_SOP SCSI over PCI-E lsm.Disk.LINK_TYPE_PCIE PCI-E, e.g. NVMe SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED Insufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt link_type_gets9cCs tt|S(s Version: 1.3 Usage: Turn on the identification LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt ident_led_on-scCs tt|S(s Version: 1.3 Usage: Turn off the identification LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR (R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt ident_led_offIscCs tt|S(s Version: 1.3 Usage: Turn on the fault LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR (R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt fault_led_onescCs tt|S(s Version: 1.3 Usage: Turn off the fault LED for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: None SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR (R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyt fault_led_offscCs tt|S(s Version: 1.3 Usage: Get LED status for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: led_status (integer, bit map) Could be combination of these values: lsm.Disk.LED_STATUS_UNKNOWN lsm.Disk.LED_STATUS_IDENT_ON lsm.Disk.LED_STATUS_IDENT_OFF lsm.Disk.LED_STATUS_IDENT_UNKNOWN Has identification LED, but status is unknown. If certain disk has no identification LED, 'led_status' should not contain 'lsm.Disk.LED_STATUS_IDENT_ON' or 'lsm.Disk.LED_STATUS_IDENT_OFF' or 'lsm.Disk.LED_STATUS_IDENT_UNKNOWN' lsm.Disk.LED_STATUS_FAULT_ON lsm.Disk.LED_STATUS_FAULT_OFF lsm.Disk.LED_STATUS_FAULT_UNKNOWN Has fault LED, but status is unknown. If certain disk has no fault LED, 'led_status' should not contain 'lsm.Disk.LED_STATUS_FAULT_ON' or 'lsm.Disk.LED_STATUS_FAULT_OFF' or 'lsm.Disk.LED_STATUS_FAULT_UNKNOWN' SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk does not support SCSI SPC. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR (R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pytled_status_gets0cCs tt|S(s Version: 1.4 Usage: Get current negotiated logical link speed for specified disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Returns: link_speed Integer for link speed in Mbps. For example, '3.0 Gbps' will get 3000. SpecialExceptions: LsmError ErrorNumber.LIB_BUG Internal bug. ErrorNumber.INVALID_ARGUMENT Invalid disk_path. Should be like '/dev/sdb'. ErrorNumber.NOT_FOUND_DISK Provided disk is not found. ErrorNumber.NO_SUPPORT Provided disk is not supported yet. ErrorNumber.PERMISSION_DENIED No sufficient permission to access provided disk path. Capability: N/A No capability required as this is a library level method. (RR(R((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pytlink_speed_gets(t__name__t __module__t staticmethodRRRRRRR R!R"R#R$R%R&(((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyR&s') ;2(tsixtlsmRRt lsm._clibRRRRRRRR R R R R RRtobjectR(((s3/usr/lib/python2.7/site-packages/lsm/_local_disk.pyts X _common.py000064400000046401147576505410006570 0ustar00# Copyright (C) 2011-2014 Red Hat, Inc. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: tasleson import hashlib import os import unittest import re import sys import syslog try: # Python 3.8 required change from collections.abc import Sequence except ImportError: from collections import Sequence import inspect try: from urllib.error import (URLError, HTTPError) from urllib.parse import urlparse except ImportError: from urllib2 import (URLError, HTTPError) from urlparse import urlparse import functools import traceback import six import ssl import socket def default_property(name, allow_set=True, doc=None): """ Creates the get/set properties for the given name. It assumes that the actual attribute is '_' + name TODO: Expand this with domain validation to ensure the values are correct. """ attribute_name = '_' + name def getter(self): return getattr(self, attribute_name) def setter(self, value): setattr(self, attribute_name, value) prop = property(getter, setter if allow_set else None, None, doc) def decorator(cls): setattr(cls, name, prop) return cls return decorator def common_urllib2_error_handler(exp): if isinstance(exp, HTTPError): raise LsmError(ErrorNumber.PLUGIN_AUTH_FAILED, str(exp)) if isinstance(exp, URLError): desc = str(exp) if 'urlopen error' in desc: if 'Errno 111' in desc: raise LsmError(ErrorNumber.NETWORK_CONNREFUSED, 'Connection refused') if 'Errno 113' in desc: raise LsmError(ErrorNumber.NETWORK_HOSTDOWN, 'Host is down') error("Unexpected network error:\n" + traceback.format_exc()) raise LsmError(ErrorNumber.NETWORK_ERROR, desc) try: if ssl.CertificateError: if isinstance(exp, ssl.CertificateError): raise LsmError(ErrorNumber.NETWORK_ERROR, "SSL Certificate error (%s)" % str(exp)) except AttributeError: pass # Python3 is the gift that keeps on giving! if six.PY3 and isinstance(exp, ConnectionError): raise LsmError(ErrorNumber.NETWORK_CONNREFUSED, str(exp)) if isinstance(exp, socket.error): raise LsmError(ErrorNumber.NETWORK_CONNREFUSED, str(exp)) stack_trace = traceback.format_exc() error("Unexpected exception:\n" + stack_trace) raise LsmError(ErrorNumber.PLUGIN_BUG, "Unexpected exception (TYPE= %s)" % str(type(exp)), stack_trace) # Documentation for Proxy class. # # Class to encapsulate the actual class we want to call. When an attempt is # made to access an attribute that doesn't exist we will raise an LsmError # instead of the default keyError. class Proxy(object): """ Used to provide an unambiguous error when a feature is not implemented. """ # The constructor. # @param self The object self # @param obj The object instance to wrap def __init__(self, obj=None): """ Constructor which takes an object to wrap. """ self.proxied_obj = obj # Called each time an attribute is requested of the object # @param self The object self # @param name Name of the attribute being accessed # @return The result of the method def __getattr__(self, name): """ Called each time an attribute is requested of the object """ if hasattr(self.proxied_obj, name): return functools.partial(self._present, name) else: raise LsmError(ErrorNumber.NO_SUPPORT, "Unsupported operation") # Method which is called to invoke the actual method of interest. # @param self The object self # @param _proxy_method_name Method to invoke # @param args Arguments # @param kwargs Keyword arguments # @return The result of the method invocation def _present(self, _proxy_method_name, *args, **kwargs): """ Method which is called to invoke the actual method of interest. """ return getattr(self.proxied_obj, _proxy_method_name)(*args, **kwargs) # variable in client and specified on the command line for the daemon UDS_PATH = '/var/run/lsm/ipc' # Set to True for verbose logging LOG_VERBOSE = True # Constant for byte size SIZE_CONS = { 'B': 1, 'KiB': 2 ** 10, 'KB': 10 ** 3, 'K': 2 ** 10, 'k': 2 ** 10, 'MiB': 2 ** 20, 'MB': 10 ** 6, 'M': 2 ** 20, 'm': 2 ** 20, 'GiB': 2 ** 30, 'GB': 10 ** 9, 'G': 2 ** 30, 'g': 2 ** 30, 'TiB': 2 ** 40, 'TB': 10 ** 12, 'T': 2 ** 40, 't': 2 ** 40, 'PiB': 2 ** 50, 'PB': 10 ** 15, 'P': 2 ** 50, 'p': 2 ** 50, 'EiB': 2 ** 60, 'EB': 10 ** 18, 'E': 2 ** 60, 'e': 2 ** 60, } SIZE_CONS_CHK_LST = ['EiB', 'PiB', 'TiB', 'GiB', 'MiB', 'KiB'] # Converts the size into human format. # @param size Size in bytes # @param human True|False # @return Human representation of size def sh(size, human=False): """ Convert size in bytes to human readable size The return string will follow IEC binary prefixes, e.g. '1.9 KiB' For size less than 1024, we do nothing but return the int we get. TODO: Need a expect to handle when size is not a int. int() might do. """ units = None if human: for key_name in SIZE_CONS_CHK_LST: if size >= SIZE_CONS[key_name]: size /= float(SIZE_CONS[key_name]) units = key_name break if not units: units = "B" return "%.2f %s" % (size, units) else: return size # Converts the size into human format. # @param size Size in bytes # @return Human representation of size in IEC binary size prefixes. def size_bytes_2_size_human(size): """ Convert integer size in bytes to human readable size. We are following rules of IEC binary prefixes on size: http://en.wikipedia.org/wiki/Gibibyte The biggest of unit this function supported is PiB. The precision is 2 which means you will get '1.99 KiB' """ return sh(size, True) # Converts the size into human format. # @param size_human Human readable size string, e.g. '1.9 KiB' # @return Size in bytes def size_human_2_size_bytes(size_human): """ Convert human readable size string into integer size in bytes. Following rules of IEC binary prefixes on size: http://en.wikipedia.org/wiki/Gibibyte Supported input size_human in these formats: '1.9KiB' # int(1024*1.9) '1 KiB' # 2**10 '1B' # 1 '2K' # 2*(2**10), treated as '2KiB' '2k' # 2*(2**10), treated as '2KiB' '2KB' # 2*(10**3) """ regex_size_human = re.compile(r""" ^ ([0-9\.]+) # 1: number [ \t]* # might have space between number and unit ([a-zA-Z]*) # 2: units $ """, re.X) regex_match = regex_size_human.match(size_human) size_bytes = 0 if regex_match: number = regex_match.group(1) units = regex_match.group(2) if not units: return int(number) units = units.upper() units = units.replace('IB', 'iB') if units in SIZE_CONS: size_bytes = SIZE_CONS[units] * float(number) return int(size_bytes) # Common method used to parse a URI. # @param uri The uri to parse # @param requires Optional list of keys that must be present in output # @param required_params Optional list of required parameters that # must be present. # @return A hash of the parsed values. def uri_parse(uri, requires=None, required_params=None): """ Common uri parse method that optionally can check for what is needed before returning successfully. """ try: rc = {} u = urlparse(uri) if u.scheme: rc['scheme'] = u.scheme if u.netloc: rc['netloc'] = u.netloc if u.port: rc['port'] = u.port if u.hostname: rc['host'] = u.hostname if u.username: rc['username'] = u.username else: rc['username'] = None rc['parameters'] = uri_parameters(u) if requires: for r in requires: if r not in rc: raise LsmError(ErrorNumber.INVALID_ARGUMENT, 'uri missing \"%s\" or is in invalid form' % r) if required_params: for r in required_params: if r not in rc['parameters']: raise LsmError(ErrorNumber.INVALID_ARGUMENT, 'uri missing query parameter %s' % r) return rc except ValueError as ve: raise LsmError(ErrorNumber.INVALID_ARGUMENT, "uri invalid: reason: %s" % str(ve)) # Parses the parameters (Query string) of the URI # @param uri Full uri # @returns hash of the query string parameters. def uri_parameters(uri): # workaround for python bug: # http://bugs.python.org/issue9374 # for URL: smispy+ssl://admin@emc-smi:5989?namespace=root/emc # Before the patch committed( RHEL 6 and Fedora 18- ): # '?namespace=root/emc' is saved in uri.path # After patched(RHEL 7 and Fedora 19+): # 'namespace=root/emc' is saved in uri.query if uri.query: query = uri.query elif uri.path: query = urlparse('http:' + uri[2]).query else: return {} if query: return dict([part.split('=') for part in query.split('&')]) else: return {} # Generates the md5 hex digest of passed in parameter. # @param t Item to generate signature on. # @returns md5 hex digest. def md5(t): h = hashlib.md5() h.update(t.encode("utf-8")) return h.hexdigest() def int_div(a, b): # Trying to avoid using past.old_div as we don't have future on all # platforms we are trying to support if six.PY3: return a // b else: return a / b # Converts a list of arguments to string. # @param args Args to join # @return string of arguments joined together. def params_to_string(*args): return ''.join([str(e) for e in args]) # Unfortunately the process name remains as 'python' so we are using argv[0] in # the output to allow us to determine which python exe is indeed logging to # syslog. # TODO: On newer versions of python this is no longer true, need to fix. # Posts a message to the syslogger. # @param level Logging level # @param prg Program name # @param msg Message to log. def post_msg(level, prg, msg): """ If a message includes new lines we will create multiple syslog entries so that the message is readable. Otherwise it isn't very readable. Hopefully we won't be logging much :-) """ for l in msg.split('\n'): if len(l): syslog.syslog(level, prg + ": " + l) def error(*msg): post_msg(syslog.LOG_ERR, os.path.basename(sys.argv[0]), params_to_string(*msg)) def info(*msg): if LOG_VERBOSE: post_msg(syslog.LOG_INFO, os.path.basename(sys.argv[0]), params_to_string(*msg)) class SocketEOF(Exception): """ Exception class to indicate when we read zero bytes from a socket. """ pass @default_property('code', doc='Error code') @default_property('msg', doc='Error message') @default_property('data', doc='Optional error data') class LsmError(Exception): def __init__(self, code, message, data=None, *args, **kwargs): """ Class represents an error. """ Exception.__init__(self, *args, **kwargs) self._code = code self._msg = message self._data = data def __str__(self): error_no_str = ErrorNumber.error_number_to_str(self.code) if self.data is not None and self.data: return "%s: %s Data: %s" % \ (error_no_str, self.msg, self.data) else: return "%s: %s " % (error_no_str, self.msg) def addl_error_data(domain, level, exception, debug=None, debug_data=None): """ Used for gathering additional information about an error. """ return {'domain': domain, 'level': level, 'exception': exception, 'debug': debug, 'debug_data': debug_data} def get_class(class_name): """ Given a class name it returns the class, caller will then need to run the constructor to create. """ parts = class_name.split('.') module = ".".join(parts[:-1]) if len(module): m = __import__(module) for comp in parts[1:]: m = getattr(m, comp) else: m = __import__('__main__') m = getattr(m, class_name) return m # Note: Some of these don't make sense for python, but they do for other # Languages so we will be keeping them consistent even though we won't be # using them. class ErrorNumber(object): OK = 0 LIB_BUG = 1 PLUGIN_BUG = 2 JOB_STARTED = 7 TIMEOUT = 11 DAEMON_NOT_RUNNING = 12 PERMISSION_DENIED = 13 NAME_CONFLICT = 50 EXISTS_INITIATOR = 52 INVALID_ARGUMENT = 101 NO_STATE_CHANGE = 125 NETWORK_CONNREFUSED = 140 # Host on network, but connection refused NETWORK_HOSTDOWN = 141 # Host unreachable on network NETWORK_ERROR = 142 # Generic network error NO_MEMORY = 152 NO_SUPPORT = 153 # Deletion related errors IS_MASKED = 160 # Volume is masked to access group. HAS_CHILD_DEPENDENCY = 161 # Volume/File system has child dependency. NOT_FOUND_ACCESS_GROUP = 200 NOT_FOUND_FS = 201 NOT_FOUND_JOB = 202 NOT_FOUND_POOL = 203 NOT_FOUND_FS_SS = 204 NOT_FOUND_VOLUME = 205 NOT_FOUND_NFS_EXPORT = 206 NOT_FOUND_SYSTEM = 208 NOT_FOUND_DISK = 209 NOT_LICENSED = 226 NO_SUPPORT_ONLINE_CHANGE = 250 NO_SUPPORT_OFFLINE_CHANGE = 251 PLUGIN_AUTH_FAILED = 300 # Client supplied credential are incorrect # Inter-process communication between client & out of process plug-in # encountered connection errors PLUGIN_IPC_FAIL = 301 # Incorrect permission on UNIX domain socket used for IPC PLUGIN_SOCKET_PERMISSION = 307 PLUGIN_NOT_EXIST = 311 NOT_ENOUGH_SPACE = 350 TRANSPORT_COMMUNICATION = 400 TRANSPORT_SERIALIZATION = 401 TRANSPORT_INVALID_ARG = 402 # refuse to remove the last initiator from access group LAST_INIT_IN_ACCESS_GROUP = 502 UNSUPPORTED_SEARCH_KEY = 510 # volume_mask() will fail if access group has no member/initiator. EMPTY_ACCESS_GROUP = 511 POOL_NOT_READY = 512 # Pool is not ready for create/resize/etc DISK_NOT_FREE = 513 # Disk is not in DISK.STATUS_FREE status. _LOCALS = locals() @staticmethod def error_number_to_str(error_no): for error_str in list(ErrorNumber._LOCALS.keys()): if ErrorNumber._LOCALS[error_str] == error_no: return "%s(%d)" % (error_str, error_no) return "UNKNOWN_ERROR_NUMBER(%d)" % error_no class JobStatus(object): INPROGRESS = 1 COMPLETE = 2 ERROR = 3 def type_compare(method_name, exp_type, act_val): if isinstance(exp_type, Sequence): if not isinstance(act_val, Sequence): raise TypeError("%s call is returning a %s, but is " "expecting a sequence" % (method_name, str(type(act_val)))) # If the list has only one expected value we will make sure all # elements in the list adhere to it, otherwise we will enforce a one # to one check against the expected types. if len(exp_type) == 1: for av in act_val: type_compare(method_name, exp_type[0], av) else: # Expect a 1-1 type match, extras get ignored at the moment for exp, act in zip(exp_type, act_val): type_compare(method_name, exp, act) else: # A number of times a method will return None or some valid type, # only check on the type if the value is not None if exp_type != type(act_val) and act_val is not None: if (isinstance(exp_type, six.string_types) and isinstance(act_val, six.string_types)): return if not inspect.isclass(exp_type) or \ not issubclass(type(act_val), exp_type): raise TypeError('%s call expected: %s got: %s ' % (method_name, str(exp_type), str(type(act_val)))) def return_requires(*types): """ Decorator function that allows us to ensure that we are getting the correct types back from a function/method call. Note: This is normally frowned upon by the python community, but this API needs to be language agnostic, so making sure we have the correct types is quite important. """ def outer(func): @functools.wraps(func) def inner(*args, **kwargs): r = func(*args, **kwargs) # In this case the user did something like # @return_requires(int, string, int) # in this case we require that all the args are present. if len(types) > 1: if len(r) != len(types): raise TypeError("%s call expected %d " "return values, actual = %d" % (func.__name__, len(types), len(r))) type_compare(func.__name__, types, r) elif len(types) == 1: # We have one return type (but it could be a sequence) type_compare(func.__name__, types[0], r) return r return inner return outer class TestCommon(unittest.TestCase): def setUp(self): pass def test_simple(self): try: raise SocketEOF() except SocketEOF as e: self.assertTrue(isinstance(e, SocketEOF)) try: raise LsmError(10, 'Message', 'Data') except LsmError as e: self.assertTrue(e.code == 10 and e.msg == 'Message' and e.data == 'Data') ed = addl_error_data('domain', 'level', 'exception', 'debug', 'debug_data') self.assertTrue(ed['domain'] == 'domain' and ed['level'] == 'level' and ed['debug'] == 'debug' and ed['exception'] == 'exception' and ed['debug_data'] == 'debug_data') def tearDown(self): pass if __name__ == '__main__': unittest.main() version.py000064400000001355147576505410006625 0ustar00# Copyright (C) 2011-2013 Red Hat, Inc. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: tasleson # To be filled in by autoconf VERSION = "1.8.1" _iplugin.pyc000064400000052122147576505410007107 0ustar00 -P`c@sddlmZddlmZddlmZmZddlm Z de ee fdYZ de fdYZ d e fd YZ d e fd YZd S(i(tABCMeta(tabstractmethod(tLsmErrort ErrorNumber(twith_metaclasstIPlugincBseZdZeddZeddZeddZeddZeddZeddZ eddZ edd Z ed d dd Z edd ZRS( sU Plug-in interface that all plug-ins must implement for basic operation. icCsdS(s Method first called to setup the plug-in (except for plugin_info) This would be the place to make a connection to the array. Returns None on success, else LsmError exception N((tselfturitpasswordttimeouttflags((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytplugin_registers cCsdS(ss Sets any time-outs for the plug-in (ms) Returns None on success, else LsmError exception N((RtmsR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt time_out_set(scCsdS(se Retrieves the current time-out Returns time-out in ms, else raise LsmError N((RR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt time_out_get1scCsdS(sZ Called when the client wants to finish up or the socket goes eof. Plug-in should clean up all resources. Note: In the case where the socket goes EOF and the plugin_unregister runs into errors the exception(s) will not be delivered to the client! Returns None on success, else LsmError exception N((RR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytplugin_unregister:s cCsdS(s Returns the stats of the given job. Returns a tuple ( status (enumeration), percent_complete, completed item). else LsmError exception. N((Rtjob_idR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt job_statusFs cCsdS(sl Frees resources for a given job. Returns None on success, else raises an LsmError N((RRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytjob_freeQscCsdS(sS Returns the capabilities for the selected system, raises LsmError N((RtsystemR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt capabilitiesZscCsdS(s Returns the description and version for plug-in, raises LsmError Note: Make sure plugin can handle this call before plugin_register is called. N((RR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt plugin_infoascCsdS(s Returns an array of pool objects. Pools are used in both block and file system interfaces, thus the reason they are in the base class. Raises LsmError on error N((Rt search_keyt search_valueR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytpoolskscCsdS(s  Returns an array of system objects. System information is used to distinguish resources from on storage array to another when the plug=in supports the ability to have more than one array managed by it Raises LsmError on error N((RR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytsystemsus N(t__name__t __module__t__doc__t_abstractmethodR R RRRRRRtNoneRR(((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyRs*     tIStorageAreaNetworkcBseZddddZddZddZddZddZddZddZ ddZ dd Z d Z dd Z dd Zdddd ZddZddZddZddZddZddZddZddZddddZRS(icCsttjddS(sV Returns an array of volume objects Raises LsmError on error s Not supportedN(RRt NO_SUPPORT(RRRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolumesscCsttjddS(s Creates a volume, given a pool, volume name, size and provisioning Returns a tuple (job_id, new volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (Rtpoolt volume_namet size_bytest provisioningR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_creates cCsttjddS(sq Deletes a volume. Returns Job id or None if completed, else raises LsmError on errors. s Not supportedN(RRR (RtvolumeR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_deletescCsttjddS(s Re-sizes a volume. Returns a tuple (job_id, re-sized_volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (RR'tnew_size_bytesR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_resizescCsttjddS(sB Replicates a volume from the specified pool. In this library, to replicate means to create a new volume which is a copy of the source. Returns a tuple (job_id, replicated volume) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (RR"trep_typet volume_srctnameR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolume_replicates cCsttjddS(s@ Returns the number of bytes per block for volume_replicate_range call. Callers of volume_replicate_range need to use this when calculating start and block lengths. Note: bytes per block may not match volume blocksize. Returns bytes per block, Raises LsmError on error s Not supportedN(RRR (RRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt!volume_replicate_range_block_sizes cCsttjddS(s+ Replicates a portion of a volume to itself or another volume. The src, dest and number of blocks values change with vendor, call volume_replicate_range_block_size to get block unit size. Returns Job id or None if completed, else raises LsmError on errors. s Not supportedN(RRR (RR+R,t volume_desttrangesR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolume_replicate_ranges cCsttjddS(sx Makes a volume available to the host Returns None on success, else raises LsmError on errors. s Not supportedN(RRR (RR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_enablescCsttjddS(sz Makes a volume unavailable to the host Returns None on success, else raises LsmError on errors. s Not supportedN(RRR (RR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolume_disablescCsttjddS(s` Register a user/password for the specified initiator for CHAP authentication. in_user & in_password are for inbound CHAP, out_user & out_password are for outbound CHAP. Note: Setting in_user, in_password or out_user, out_password to None will disable authentication. Raises LsmError on error s Not supportedN(RRR (Rtinit_idtin_usert in_passwordtout_usert out_passwordR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytiscsi_chap_auths cCsttjddS(s~ Allows an access group to access a volume. Returns None on success, else raises LsmError on errors. s Not supportedN(RRR (Rt access_groupR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_maskscCsttjddS(s Revokes access for an access group for a volume Returns None on success, else raises LsmError on errors. s Not supportedN(RRR (RR;R'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt volume_unmaskscCsttjddS(sM Returns a list of access groups, raises LsmError on errors. s Not supportedN(RRR (RRRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt access_groupsscCsttjddS(sM Returns a list of access groups, raises LsmError on errors. s Not supportedN(RRR (RR-R5t init_typeRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytaccess_group_createscCsttjddS(sC Deletes an access group, Raises LsmError on error s Not supportedN(RRR (RR;R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytaccess_group_deletescCsttjddS(sP Adds an initiator to an access group, Raises LsmError on error s Not supportedN(RRR (RR;R5R?R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytaccess_group_initiator_add scCsttjddS(sU Deletes an initiator from an access group, Raises LsmError on error s Not supportedN(RRR (RR;R5R?R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytaccess_group_initiator_deletescCsttjddS(so Returns the list of volumes that access group has access to. Raises LsmError on error s Not supportedN(RRR (RR;R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt"volumes_accessible_by_access_groupscCsttjddS(sw Returns the list of access groups that have access to the specified, Raises LsmError on error s Not supportedN(RRR (RR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytaccess_groups_granted_to_volume scCsttjddS(s Returns True if this volume has other volumes which are dependant on it. Implies that this volume cannot be deleted or possibly modified because it would affect its children. s Not supportedN(RRR (RR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolume_child_dependency'scCsttjddS(s If this volume has child dependency, this method call will fully replicate the blocks removing the relationship between them. This should return None (success) if volume_child_dependency would return False. Note: This operation could take a very long time depending on the size of the volume and the number of child dependencies. Returns None if complete else job id, raises LsmError on errors. s Not supportedN(RRR (RR'R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytvolume_child_dependency_rm/s cCsttjddS(Ns Not supported(RRR (RRRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt target_ports=sN(RRRR!R&R(R*R.R/R2R3R4R:R<R=R>R@RARBRCRDRERFRGRH(((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyRs,              tINetworkAttachedStoragecBseZdZddddZddZddZddZdddZdddZ ddZ dd Z dd Z e dd Zdd Zdd ZRS(sT Class the represents Network attached storage (Common NFS/CIFS operations) icCsdS(sf Returns a list of file systems on the controller. Raises LsmError on errors. N((RRRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfsEscCsttjddS(s WARNING: Destructive Deletes a file system and everything it contains Returns None on success, else job id s Not supportedN(RRR (RRJR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt fs_deleteLscCsttjddS(s Re-size a file system Returns a tuple (job_id, re-sized file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (RRJR)R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt fs_resizeUscCsttjddS(sO Creates a file system given a pool, name and size. Note: size is limited to 2**64 bytes so max size of a single volume at this time is 16 Exabytes Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (RR"R-R$R ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt fs_create_s cCsttjddS(s# Creates a thin, point in time read/writable copy of src to dest. Optionally uses snapshot as backing of src_fs Returns a tuple (job_id, file system) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. s Not supportedN(RRR (Rtsrc_fst dest_fs_nametsnapshotR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_cloneks cCsttjddS(s Creates a thinly provisioned clone of src to dest. Note: Source and Destination are required to be on same filesystem Returns Job id or None if completed, else raises LsmError on errors. s Not supportedN(RRR (RRJt src_file_nametdest_file_nameRPR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt fs_file_clonevscCsttjddS(sl Returns a list of snapshots for the supplied file system, Raises LsmError on error s Not supportedN(RRR (RRJR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt fs_snapshotsscCsttjddS(s{ Snapshot is a point in time read-only copy Create a snapshot on the chosen file system Returns a tuple (job_id, snap shot created) Note: Tuple return values are mutually exclusive, when one is None the other must be valid. Note: Snapshot name may not match what was passed in (depends on array implementation) s Not supportedN(RRR (RRJt snapshot_nameR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_snapshot_creates cCsttjddS(s Frees the re-sources for the given snapshot on the supplied filesystem. Returns Job id or None if completed, else raises LsmError on errors. s Not supportedN(RRR (RRJRPR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_snapshot_deletescCsttjddS(s< WARNING: Destructive! Reverts a file-system or just the specified files from the snapshot. If a list of files is supplied but the array cannot restore just them then the operation will fail with an LsmError raised. If files == None and all_files = True then all files on the file-system are restored. Restore_file if not None must be the same length as files with each index in each list referring to the associated file. Returns None on success, else job id, LsmError exception on error s Not supportedN(RRR (RRJRPtfilest restore_filest all_filesR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_snapshot_restorescCsttjddS(s& Returns True if the specified filesystem or specified file on this file system has child dependencies. This implies that this filesystem or specified file on this file system cannot be deleted or possibly modified because it would affect its children. s Not supportedN(RRR (RRJRYR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_child_dependencyscCsttjddS(s If this filesystem or specified file on this filesystem has child dependency this method will fully replicate the blocks removing the relationship between them. This should return None(success) if fs_child_dependency would return False. Note: This operation could take a very long time depending on the size of the filesystem and the number of child dependencies. Returns Job id or None if completed, else raises LsmError on errors. s Not supportedN(RRR (RRJRYR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytfs_child_dependency_rms N(RRRRRJRKRLRMRQRTRURWRXtFalseR\R]R^(((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyRIAs      tINfscBs>eZddZddddZddZddZRS(icCsttjddS(sP Returns the types of authentication that are available for NFS s Not supportedN(RRR (RR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt export_authscCsttjddS(sL Get a list of all exported file systems on the controller. s Not supportedN(RRR (RRRR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytexportssc CsttjddS(sA Exports a filesystem as specified in the export s Not supportedN(RRR ( Rtfs_idt export_patht root_listtrw_listtro_listtanon_uidtanon_gidt auth_typetoptionsR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt export_fsscCsttjddS(s. Removes the specified export s Not supportedN(RRR (RtexportR ((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyt export_removesN(RRRaRRbRlRn(((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pyR`s  N(tabcRt_ABCMetaRRtlsmRRtsixRtobjectRRRIR`(((s0/usr/lib/python2.7/site-packages/lsm/_iplugin.pytsj_data.py000064400000110707147576505410006212 0ustar00# Copyright (C) 2011-2016 Red Hat, Inc. # (C) Copyright 2016-2017 Hewlett Packard Enterprise Development LP # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: tasleson # Gris Ge # Joe Handzik from abc import ABCMeta as _ABCMeta import re import binascii from six import with_metaclass try: import simplejson as json except ImportError: import json from json.decoder import WHITESPACE from lsm._common import get_class, default_property, ErrorNumber, LsmError import six class DataEncoder(json.JSONEncoder): """ Custom json encoder for objects derived form ILsmData """ def default(self, my_class): if not isinstance(my_class, IData): raise ValueError('incorrect class type:' + str(type(my_class))) else: return my_class._to_dict() class DataDecoder(json.JSONDecoder): """ Custom json decoder for objects derived from ILsmData """ @staticmethod def __process_dict(d): """ Processes a dictionary """ rc = {} if 'class' in d: rc = IData._factory(d) else: for (k, v) in d.items(): rc[k] = DataDecoder.__decode(v) return rc @staticmethod def __process_list(l): """ Processes a list """ rc = [] for elem, value in enumerate(l): if type(value) is list: rc.append(DataDecoder.__process_list(value)) elif type(value) is dict: rc.append(DataDecoder.__process_dict(value)) else: rc.append(value) return rc @staticmethod def __decode(e): """ Decodes the parsed json """ if type(e) is dict: return DataDecoder.__process_dict(e) elif type(e) is list: return DataDecoder.__process_list(e) else: return e def decode(self, json_string, _w=WHITESPACE.match): return DataDecoder.__decode(json.loads(json_string)) class IData(with_metaclass(_ABCMeta, object)): """ Base class functionality of serializable classes. """ def _to_dict(self): """ Represent the class as a dictionary """ rc = {'class': self.__class__.__name__} # If one of the attributes is another IData we will # process that too, is there a better way to handle this? for (k, v) in list(self.__dict__.items()): if isinstance(v, IData): rc[k[1:]] = v._to_dict() else: rc[k[1:]] = v return rc @staticmethod def _factory(d): """ Factory for creating the appropriate class given a dictionary. This only works for objects that inherit from IData """ if 'class' in d: class_name = d['class'] del d['class'] c = get_class(__name__ + '.' + class_name) # If any of the parameters are themselves an IData process them for k, v in list(d.items()): if isinstance(v, dict) and 'class' in v: d['_' + k] = IData._factory(d.pop(k)) else: d['_' + k] = d.pop(k) return c(**d) def __str__(self): """ Used for human string representation. """ return str(self._to_dict()) @default_property('id', doc="Unique identifier") @default_property('name', doc="Disk name (aka. vendor)") @default_property('disk_type', doc="Enumerated type of disk") @default_property('block_size', doc="Size of each block") @default_property('num_of_blocks', doc="Total number of blocks") @default_property('status', doc="Enumerated status") @default_property('system_id', doc="System identifier") @default_property("plugin_data", doc="Private plugin data") class Disk(IData): """ Represents a disk. """ SUPPORTED_SEARCH_KEYS = ['id', 'system_id'] # We use '-1' to indicate we failed to get the requested number. # For example, when block found is undetectable, we use '-1' instead of # confusing 0. BLOCK_COUNT_NOT_FOUND = -1 BLOCK_SIZE_NOT_FOUND = -1 TYPE_UNKNOWN = 0 TYPE_OTHER = 1 TYPE_ATA = 3 # IDE disk which is seldomly used. TYPE_SATA = 4 TYPE_SAS = 5 TYPE_FC = 6 TYPE_SOP = 7 # SCSI over PCIe(SSD) TYPE_SCSI = 8 TYPE_LUN = 9 # Remote LUN was treated as a disk. # Due to complexity of disk types, we are defining these beside DMTF # standards: TYPE_NL_SAS = 51 # Near-Line SAS==SATA disk + SAS port. # in DMTF CIM 2.34.0+ CIM_DiskDrive['DiskType'], they also defined # SSD and HYBRID disk type. We use it as fallback. TYPE_HDD = 52 # Normal HDD TYPE_SSD = 53 # Solid State Drive TYPE_HYBRID = 54 # uses a combination of HDD and SSD STATUS_UNKNOWN = 1 << 0 STATUS_OK = 1 << 1 STATUS_OTHER = 1 << 2 STATUS_PREDICTIVE_FAILURE = 1 << 3 STATUS_ERROR = 1 << 4 STATUS_REMOVED = 1 << 5 STATUS_STARTING = 1 << 6 STATUS_STOPPING = 1 << 7 STATUS_STOPPED = 1 << 8 STATUS_INITIALIZING = 1 << 9 STATUS_MAINTENANCE_MODE = 1 << 10 # In maintenance for bad sector scan, integrity check and etc # It might be combined with STATUS_OK or # STATUS_STOPPED for online maintenance or offline maintenance. STATUS_SPARE_DISK = 1 << 11 # Indicate disk is a spare disk. STATUS_RECONSTRUCT = 1 << 12 # Indicate disk is reconstructing data. STATUS_FREE = 1 << 13 # New in version 1.2, indicate the whole disk is not holding any data or # acting as a dedicate spare disk. # This disk could be assigned as a dedicated spare disk or used for # creating pool. # If any spare disk(like those on NetApp ONTAP) does not require # any explicit action when assigning to pool, it should be treated as # free disk and marked as STATUS_FREE|STATUS_SPARE_DISK. RPM_NO_SUPPORT = -2 RPM_UNKNOWN = -1 RPM_NON_ROTATING_MEDIUM = 0 RPM_ROTATING_UNKNOWN_SPEED = 1 LINK_TYPE_NO_SUPPORT = -2 LINK_TYPE_UNKNOWN = -1 LINK_TYPE_FC = 0 LINK_TYPE_SSA = 2 LINK_TYPE_SBP = 3 LINK_TYPE_SRP = 4 LINK_TYPE_ISCSI = 5 LINK_TYPE_SAS = 6 LINK_TYPE_ADT = 7 LINK_TYPE_ATA = 8 LINK_TYPE_USB = 9 LINK_TYPE_SOP = 10 LINK_TYPE_PCIE = 11 LED_STATUS_UNKNOWN = 1 << 0 LED_STATUS_IDENT_ON = 1 << 1 LED_STATUS_IDENT_OFF = 1 << 2 LED_STATUS_IDENT_UNKNOWN = 1 << 3 LED_STATUS_FAULT_ON = 1 << 4 LED_STATUS_FAULT_OFF = 1 << 5 LED_STATUS_FAULT_UNKNOWN = 1 << 6 LINK_SPEED_UNKNOWN = 0 HEALTH_STATUS_UNKNOWN = -1 HEALTH_STATUS_FAIL = 0 HEALTH_STATUS_WARN = 1 HEALTH_STATUS_GOOD = 2 def __init__(self, _id, _name, _disk_type, _block_size, _num_of_blocks, _status, _system_id, _plugin_data=None, _vpd83='', _location='', _rpm=RPM_NO_SUPPORT, _link_type=LINK_TYPE_NO_SUPPORT): self._id = _id self._name = _name self._disk_type = _disk_type self._block_size = _block_size self._num_of_blocks = _num_of_blocks self._status = _status self._system_id = _system_id self._plugin_data = _plugin_data if _vpd83 and not Volume.vpd83_verify(_vpd83): raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Incorrect format of VPD 0x83 NAA(3) string: '%s', " "expecting 32 or 16 lower case hex characters" % _vpd83) self._vpd83 = _vpd83 self._location = _location self._rpm = _rpm self._link_type = _link_type @property def size_bytes(self): """ Disk size in bytes. """ return self.block_size * self.num_of_blocks @property def vpd83(self): """ String. SCSI VPD83 ID. New in version 1.3. Only available for DAS(direct attached storage) systems. The VPD83 ID could be used in 'lsm.SCSI.disk_paths_of_vpd83()' when physical disk is exposed to OS directly. """ if self._vpd83 == '': raise LsmError( ErrorNumber.NO_SUPPORT, "Disk.vpd83 is not supported by current disk or plugin") return self._vpd83 @property def location(self): """ String. Disk location in storage topology. New in version 1.3. """ if self._location == '': raise LsmError(ErrorNumber.NO_SUPPORT, "Disk.location property is not supported by this " "plugin yet") return self._location @property def rpm(self): """ Integer. New in version 1.3. Disk rotation speed - revolutions per minute(RPM): -1 (LSM_DISK_RPM_UNKNOWN): Unknown RPM 0 (LSM_DISK_RPM_NON_ROTATING_MEDIUM): Non-rotating medium (e.g., SSD) 1 (LSM_DISK_RPM_ROTATING_UNKNOWN_SPEED): Rotational disk with unknown speed >1: Normal rotational disk (e.g., HDD) """ if self._rpm == Disk.RPM_NO_SUPPORT: raise LsmError(ErrorNumber.NO_SUPPORT, "Disk.rpm is not supported by this plugin yet") return self._rpm @property def link_type(self): """ Integer. New in version 1.3. Link type, possible values are: lsm.Disk.LINK_TYPE_UNKNOWN Failed to detect link type lsm.Disk.LINK_TYPE_FC Fibre Channel lsm.Disk.LINK_TYPE_SSA Serial Storage Architecture, Old IBM tech. lsm.Disk.LINK_TYPE_SBP Serial Bus Protocol, used by IEEE 1394. lsm.Disk.LINK_TYPE_SRP SCSI RDMA Protocol lsm.Disk.LINK_TYPE_ISCSI Internet Small Computer System Interface lsm.Disk.LINK_TYPE_SAS Serial Attached SCSI lsm.Disk.LINK_TYPE_ADT Automation/Drive Interface Transport Protocol, often used by Tape. lsm.Disk.LINK_TYPE_ATA PATA/IDE or SATA. lsm.Disk.LINK_TYPE_USB USB disk. lsm.Disk.LINK_TYPE_SOP SCSI over PCI-E lsm.Disk.LINK_TYPE_PCIE PCI-E, e.g. NVMe """ if self._link_type == Disk.LINK_TYPE_NO_SUPPORT: raise LsmError(ErrorNumber.NO_SUPPORT, "Disk.link_type is not supported by this plugin " "yet") return self._link_type def __str__(self): return self.name # Lets do this once outside of the class to minimize the number of # times it needs to be compiled. _vol_regex_vpd83 = re.compile('(?:^6[0-9a-f]{31})|(?:^[235][0-9a-f]{15})$') @default_property('id', doc="Unique identifier") @default_property('name', doc="User given name") @default_property('vpd83', doc="Vital product page 0x83 identifier") @default_property('block_size', doc="Volume block size") @default_property('num_of_blocks', doc="Number of blocks") @default_property('admin_state', doc="Enabled or disabled by administrator") @default_property('system_id', doc="System identifier") @default_property('pool_id', doc="Pool identifier") @default_property("plugin_data", doc="Private plugin data") class Volume(IData): """ Represents a volume. """ SUPPORTED_SEARCH_KEYS = ['id', 'system_id', 'pool_id'] # Replication types REPLICATE_UNKNOWN = -1 REPLICATE_CLONE = 2 REPLICATE_COPY = 3 REPLICATE_MIRROR_SYNC = 4 REPLICATE_MIRROR_ASYNC = 5 # Provisioning types PROVISION_UNKNOWN = -1 PROVISION_THIN = 1 PROVISION_FULL = 2 PROVISION_DEFAULT = 3 ADMIN_STATE_DISABLED = 0 ADMIN_STATE_ENABLED = 1 RAID_TYPE_UNKNOWN = -1 # The plugin failed to detect the volume's RAID type. RAID_TYPE_RAID0 = 0 # Stripe RAID_TYPE_RAID1 = 1 # Mirror for two disks. For 4 disks or more, they are RAID10. RAID_TYPE_RAID3 = 3 # Byte-level striping with dedicated parity RAID_TYPE_RAID4 = 4 # Block-level striping with dedicated parity RAID_TYPE_RAID5 = 5 # Block-level striping with distributed parity RAID_TYPE_RAID6 = 6 # Block-level striping with two distributed parities, aka, RAID-DP RAID_TYPE_RAID10 = 10 # Stripe of mirrors RAID_TYPE_RAID15 = 15 # Parity of mirrors RAID_TYPE_RAID16 = 16 # Dual parity of mirrors RAID_TYPE_RAID50 = 50 # Stripe of parities RAID_TYPE_RAID60 = 60 # Stripe of dual parities RAID_TYPE_RAID51 = 51 # Mirror of parities RAID_TYPE_RAID61 = 61 # Mirror of dual parities RAID_TYPE_JBOD = 20 # Just bunch of disks, no parity, no striping. RAID_TYPE_MIXED = 21 # This volume contains multiple RAID settings. RAID_TYPE_OTHER = 22 # Vendor specific RAID type STRIP_SIZE_UNKNOWN = 0 DISK_COUNT_UNKNOWN = 0 MIN_IO_SIZE_UNKNOWN = 0 OPT_IO_SIZE_UNKNOWN = 0 VCR_STRIP_SIZE_DEFAULT = 0 WRITE_CACHE_POLICY_UNKNOWN = 1 WRITE_CACHE_POLICY_WRITE_BACK = 2 WRITE_CACHE_POLICY_AUTO = 3 WRITE_CACHE_POLICY_WRITE_THROUGH = 4 WRITE_CACHE_STATUS_UNKNOWN = 1 WRITE_CACHE_STATUS_WRITE_BACK = 2 WRITE_CACHE_STATUS_WRITE_THROUGH = 3 READ_CACHE_POLICY_UNKNOWN = 1 READ_CACHE_POLICY_ENABLED = 2 READ_CACHE_POLICY_DISABLED = 3 READ_CACHE_STATUS_UNKNOWN = 1 READ_CACHE_STATUS_ENABLED = 2 READ_CACHE_STATUS_DISABLED = 3 PHYSICAL_DISK_CACHE_UNKNOWN = 1 PHYSICAL_DISK_CACHE_ENABLED = 2 PHYSICAL_DISK_CACHE_DISABLED = 3 PHYSICAL_DISK_CACHE_USE_DISK_SETTING = 4 def __init__(self, _id, _name, _vpd83, _block_size, _num_of_blocks, _admin_state, _system_id, _pool_id, _plugin_data=None): self._id = _id # Identifier self._name = _name # Human recognisable name if _vpd83 and not Volume.vpd83_verify(_vpd83): raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Incorrect format of VPD 0x83 NAA(3) string: '%s', " "expecting 32 or 16 lower case hex characters" % _vpd83) self._vpd83 = _vpd83 # SCSI page 83 unique ID self._block_size = _block_size # Block size self._num_of_blocks = _num_of_blocks # Number of blocks self._admin_state = _admin_state # enable or disabled by admin self._system_id = _system_id # System id this volume belongs self._pool_id = _pool_id # Pool id this volume belongs self._plugin_data = _plugin_data @property def size_bytes(self): """ Volume size in bytes. """ return self.block_size * self.num_of_blocks def __str__(self): return self.name @staticmethod def vpd83_verify(vpd): """ Returns True if string is valid vpd 0x83 representation """ if vpd and _vol_regex_vpd83.match(vpd): return True return False @default_property('id', doc="Unique identifier") @default_property('name', doc="User defined system name") @default_property('status', doc="Enumerated status of system") @default_property('status_info', doc="Detail status information of system") @default_property("plugin_data", doc="Private plugin data") class System(IData): STATUS_UNKNOWN = 1 << 0 STATUS_OK = 1 << 1 STATUS_ERROR = 1 << 2 STATUS_DEGRADED = 1 << 3 STATUS_PREDICTIVE_FAILURE = 1 << 4 STATUS_OTHER = 1 << 5 MODE_NO_SUPPORT = -2 MODE_UNKNOWN = -1 MODE_HARDWARE_RAID = 0 MODE_HBA = 1 READ_CACHE_PCT_NO_SUPPORT = -2 READ_CACHE_PCT_UNKNOWN = -1 def __init__(self, _id, _name, _status, _status_info, _plugin_data=None, _fw_version='', _mode=None, _read_cache_pct=None): self._id = _id self._name = _name self._status = _status self._status_info = _status_info self._plugin_data = _plugin_data self._fw_version = _fw_version if _read_cache_pct is None: self._read_cache_pct = System.READ_CACHE_PCT_NO_SUPPORT else: self._read_cache_pct = _read_cache_pct if _mode is None: self._mode = System.MODE_NO_SUPPORT else: self._mode = _mode @property def fw_version(self): """ String. Firmware version string. New in version 1.3. On some system, it might contain multiple version strings, example: "Package: 23.32.0-0009, FW: 3.440.05-3712" """ if self._fw_version == '': raise LsmError(ErrorNumber.NO_SUPPORT, "System.fw_version() is not supported by this " "plugin yet") return self._fw_version @property def mode(self): """ Integer(enumerated value). System mode. New in version 1.3. Only available for HW RAID systems at this time. Possible values: * lsm.System.MODE_HARDWARE_RAID The logical volume(aka, RAIDed virtual disk) can be exposed to OS while hardware RAID card is handling the RAID algorithm. Physical disk can not be exposed to OS directly. * lsm.System.MODE_HBA The physical disks can be exposed to OS directly. SCSI enclosure service might be exposed to OS also. """ if self._mode == System.MODE_NO_SUPPORT: raise LsmError(ErrorNumber.NO_SUPPORT, "System.mode is not supported by this plugin yet") return self._mode @property def read_cache_pct(self): """ Integer. Read cache percentage. New in version 1.3. Possible values: * 0-100 The read cache percentage. The write cache percentage will then be 100 - read_cache_pct """ if self._read_cache_pct == System.READ_CACHE_PCT_NO_SUPPORT: raise LsmError(ErrorNumber.NO_SUPPORT, "System.read_cache_pct is not supported by this " "plugin yet") return self._read_cache_pct @default_property('id', doc="Unique identifier") @default_property('name', doc="User supplied name") @default_property('total_space', doc="Total space in bytes") @default_property('free_space', doc="Free space in bytes") @default_property('status', doc="Enumerated status") @default_property('status_info', doc="Text explaining status") @default_property('system_id', doc="System identifier") @default_property("plugin_data", doc="Plug-in private data") @default_property("element_type", doc="What pool can be used for") @default_property("unsupported_actions", doc="What cannot be done with this pool") class Pool(IData): """ Pool specific information """ SUPPORTED_SEARCH_KEYS = ['id', 'system_id'] TOTAL_SPACE_NOT_FOUND = -1 FREE_SPACE_NOT_FOUND = -1 # Element Type indicate what kind of element could this pool create: # * Another Pool # * Volume (aka, LUN) # * System Reserved Pool. ELEMENT_TYPE_POOL = 1 << 1 ELEMENT_TYPE_VOLUME = 1 << 2 ELEMENT_TYPE_FS = 1 << 3 ELEMENT_TYPE_DELTA = 1 << 4 ELEMENT_TYPE_VOLUME_FULL = 1 << 5 ELEMENT_TYPE_VOLUME_THIN = 1 << 6 ELEMENT_TYPE_SYS_RESERVED = 1 << 10 # Reserved for system use # Unsupported actions, what pool cannot be used for UNSUPPORTED_VOLUME_GROW = 1 << 0 UNSUPPORTED_VOLUME_SHRINK = 1 << 1 # Pool status could be any combination of these status. STATUS_UNKNOWN = 1 << 0 STATUS_OK = 1 << 1 STATUS_OTHER = 1 << 2 STATUS_DEGRADED = 1 << 4 STATUS_ERROR = 1 << 5 STATUS_STOPPED = 1 << 9 STATUS_RECONSTRUCTING = 1 << 12 STATUS_VERIFYING = 1 << 13 STATUS_INITIALIZING = 1 << 14 STATUS_GROWING = 1 << 15 MEMBER_TYPE_UNKNOWN = 0 MEMBER_TYPE_OTHER = 1 MEMBER_TYPE_DISK = 2 MEMBER_TYPE_POOL = 3 def __init__(self, _id, _name, _element_type, _unsupported_actions, _total_space, _free_space, _status, _status_info, _system_id, _plugin_data=None): self._id = _id # Identifier self._name = _name # Human recognisable name self._element_type = _element_type # What pool can be used to create # What pool cannot be used for self._unsupported_actions = _unsupported_actions self._total_space = _total_space # Total size self._free_space = _free_space # Free space available self._status = _status # Status of pool. self._status_info = _status_info # Additional status text of pool self._system_id = _system_id # System id this pool belongs self._plugin_data = _plugin_data # Plugin private data @default_property('id', doc="Unique identifier") @default_property('name', doc="File system name") @default_property('total_space', doc="Total space in bytes") @default_property('free_space', doc="Free space available") @default_property('pool_id', doc="What pool the file system resides on") @default_property('system_id', doc="System ID") @default_property("plugin_data", doc="Private plugin data") class FileSystem(IData): SUPPORTED_SEARCH_KEYS = ['id', 'system_id', 'pool_id'] def __init__(self, _id, _name, _total_space, _free_space, _pool_id, _system_id, _plugin_data=None): self._id = _id self._name = _name self._total_space = _total_space self._free_space = _free_space self._pool_id = _pool_id self._system_id = _system_id self._plugin_data = _plugin_data @default_property('id', doc="Unique identifier") @default_property('name', doc="Snapshot name") @default_property('ts', doc="Time stamp the snapshot was created") @default_property("plugin_data", doc="Private plugin data") class FsSnapshot(IData): def __init__(self, _id, _name, _ts, _plugin_data=None): self._id = _id self._name = _name self._ts = int(_ts) self._plugin_data = _plugin_data @default_property('id', doc="Unique identifier") @default_property('fs_id', doc="Filesystem that is exported") @default_property('export_path', doc="Export path") @default_property('auth', doc="Authentication type") @default_property('root', doc="List of hosts with no_root_squash") @default_property('rw', doc="List of hosts with Read & Write privileges") @default_property('ro', doc="List of hosts with Read only privileges") @default_property('anonuid', doc="UID for anonymous user id") @default_property('anongid', doc="GID for anonymous group id") @default_property('options', doc="String containing advanced options") @default_property('plugin_data', doc="Plugin private data") class NfsExport(IData): SUPPORTED_SEARCH_KEYS = ['id', 'fs_id'] ANON_UID_GID_NA = -1 ANON_UID_GID_ERROR = -2 def __init__(self, _id, _fs_id, _export_path, _auth, _root, _rw, _ro, _anonuid, _anongid, _options, _plugin_data=None): assert (_fs_id is not None) assert (_export_path is not None) self._id = _id self._fs_id = _fs_id # File system exported self._export_path = _export_path # Export path self._auth = _auth # Authentication type self._root = _root # List of hosts with no_root_squash self._rw = _rw # List of hosts with read/write self._ro = _ro # List of hosts with read/only self._anonuid = _anonuid # uid for anonymous user id self._anongid = _anongid # gid for anonymous group id self._options = _options # NFS options self._plugin_data = _plugin_data @default_property('src_block', doc="Source logical block address") @default_property('dest_block', doc="Destination logical block address") @default_property('block_count', doc="Number of blocks") class BlockRange(IData): def __init__(self, _src_block, _dest_block, _block_count): self._src_block = _src_block self._dest_block = _dest_block self._block_count = _block_count @default_property('id', doc="Unique instance identifier") @default_property('name', doc="Access group name") @default_property('init_ids', doc="List of initiator IDs") @default_property('init_type', doc="Initiator type") @default_property('system_id', doc="System identifier") @default_property('plugin_data', doc="Plugin private data") class AccessGroup(IData): SUPPORTED_SEARCH_KEYS = ['id', 'system_id'] INIT_TYPE_UNKNOWN = 0 INIT_TYPE_OTHER = 1 INIT_TYPE_WWPN = 2 INIT_TYPE_ISCSI_IQN = 5 INIT_TYPE_ISCSI_WWPN_MIXED = 7 def __init__(self, _id, _name, _init_ids, _init_type, _system_id, _plugin_data=None): self._id = _id self._name = _name # AccessGroup name # A list of Initiator ID strings. self._init_ids = AccessGroup._standardize_init_list(_init_ids) self._init_type = _init_type self._system_id = _system_id # System id this group belongs self._plugin_data = _plugin_data @staticmethod def _standardize_init_list(init_ids): rc = [] for i in init_ids: valid, init_type, init_id = AccessGroup.initiator_id_verify(i) if valid: rc.append(init_id) else: raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Invalid initiator ID %s" % i) return rc _regex_wwpn = re.compile(r""" ^(0x|0X)?([0-9A-Fa-f]{2}) (([\.:\-])?[0-9A-Fa-f]{2}){7}$ """, re.X) @staticmethod def initiator_id_verify(init_id, init_type=None, raise_exception=False): """ Public method which can be used to verify an initiator id :param init_id: :param init_type: :param raise_exception: Will throw a LsmError INVALID_ARGUMENT if not a valid initiator address :return:(Bool, init_type, init_id) Note: init_id will be returned in normalized format if it's a WWPN """ if init_id.startswith('iqn') or init_id.startswith('eui') or\ init_id.startswith('naa'): if init_type is None or \ init_type == AccessGroup.INIT_TYPE_ISCSI_IQN: return True, AccessGroup.INIT_TYPE_ISCSI_IQN, init_id if AccessGroup._regex_wwpn.match(str(init_id)): if init_type is None or \ init_type == AccessGroup.INIT_TYPE_WWPN: return (True, AccessGroup.INIT_TYPE_WWPN, AccessGroup._wwpn_to_lsm_type(init_id)) if raise_exception: raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Initiator id '%s' is invalid" % init_id) return False, None, None @staticmethod def _wwpn_to_lsm_type(wwpn, raise_error=True): """ Convert provided WWPN string into LSM standard one: LSM WWPN format: ^(?:[0-9a-f]{2}:){7}[0-9a-f]{2}$ LSM WWPN Example: 10:00:00:00:c9:95:2f:de Acceptable WWPN format is: ^[0x|0X]{0,1}(:?[0-9A-Fa-f]{2}[\.\-:]{0,1}){7}[0-9A-Fa-f]{2}$ Acceptable WWPN example: 10:00:00:00:c9:95:2f:de 10:00:00:00:C9:95:2F:DE 10-00-00-00-C9-95-2F-DE 10-00-00-00-c9-95-2f-de 10.00.00.00.C9.95.2F.DE 10.00.00.00.c9.95.2f.de 0x10000000c9952fde 0X10000000C9952FDE 10000000c9952fde 10000000C9952FDE Return the LSM WWPN Return None if raise_error is False and not a valid WWPN. """ if AccessGroup._regex_wwpn.match(str(wwpn)): s = str(wwpn) s = s.lower() s = re.sub(r'0x', '', s) s = re.sub(r'[^0-9a-f]', '', s) s = ":".join(re.findall(r'..', s)) return s if raise_error: raise LsmError(ErrorNumber.INVALID_ARGUMENT, "Invalid WWPN Initiator: %s" % wwpn) return None @default_property('id', doc="Unique instance identifier") @default_property('port_type', doc="Target port type") @default_property('service_address', doc="Target port service address") @default_property('network_address', doc="Target port network address") @default_property('physical_address', doc="Target port physical address") @default_property('physical_name', doc="Target port physical port name") @default_property('system_id', doc="System identifier") @default_property('plugin_data', doc="Plugin private data") class TargetPort(IData): SUPPORTED_SEARCH_KEYS = ['id', 'system_id'] TYPE_OTHER = 1 TYPE_FC = 2 TYPE_FCOE = 3 TYPE_ISCSI = 4 def __init__(self, _id, _port_type, _service_address, _network_address, _physical_address, _physical_name, _system_id, _plugin_data=None): self._id = _id self._port_type = _port_type self._service_address = _service_address # service_address: # The address used by upper layer like FC and iSCSI: # FC and FCoE: WWPN # iSCSI: IQN # String. Lower case, split with : every two digits if WWPN. self._network_address = _network_address # network_address: # The address used by network layer like FC and TCP/IP: # FC/FCoE: WWPN # iSCSI: IPv4:Port # [IPv6]:Port # String. Lower case, split with : every two digits if WWPN. self._physical_address = _physical_address # physical_address: # The address used by physical layer like FC-0 and MAC: # FC: WWPN # FCoE: WWPN # iSCSI: MAC # String. Lower case, split with : every two digits. self._physical_name = _physical_name # physical_name # The name of physical port. Administrator could use this name to # locate the port on storage system. # String. self._system_id = _system_id self._plugin_data = _plugin_data class Capabilities(IData): UNSUPPORTED = 0 SUPPORTED = 1 _NUM = 512 # Indicate the maximum capability integer _CAP_NUM_BEGIN = 20 # Indicate the first capability integer # Block operations VOLUMES = 20 VOLUME_CREATE = 21 VOLUME_RESIZE = 22 VOLUME_REPLICATE = 23 VOLUME_REPLICATE_CLONE = 24 VOLUME_REPLICATE_COPY = 25 VOLUME_REPLICATE_MIRROR_ASYNC = 26 VOLUME_REPLICATE_MIRROR_SYNC = 27 VOLUME_COPY_RANGE_BLOCK_SIZE = 28 VOLUME_COPY_RANGE = 29 VOLUME_COPY_RANGE_CLONE = 30 VOLUME_COPY_RANGE_COPY = 31 VOLUME_DELETE = 33 VOLUME_ENABLE = 34 VOLUME_DISABLE = 35 VOLUME_MASK = 36 VOLUME_UNMASK = 37 ACCESS_GROUPS = 38 ACCESS_GROUP_CREATE_WWPN = 39 ACCESS_GROUP_DELETE = 40 ACCESS_GROUP_INITIATOR_ADD_WWPN = 41 # For empty access group, this indicate it can add WWPN into it. ACCESS_GROUP_INITIATOR_DELETE = 42 VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP = 43 ACCESS_GROUPS_GRANTED_TO_VOLUME = 44 VOLUME_CHILD_DEPENDENCY = 45 VOLUME_CHILD_DEPENDENCY_RM = 46 ACCESS_GROUP_CREATE_ISCSI_IQN = 47 ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN = 48 # For empty access group, this indicate it can add iSCSI IQN into it. VOLUME_ISCSI_CHAP_AUTHENTICATION = 53 VOLUME_RAID_INFO = 54 VOLUME_THIN = 55 BATTERIES = 56 VOLUME_CACHE_INFO = 57 VOLUME_PHYSICAL_DISK_CACHE_UPDATE = 58 VOLUME_PHYSICAL_DISK_CACHE_UPDATE_SYSTEM_LEVEL = 59 VOLUME_WRITE_CACHE_POLICY_UPDATE_WRITE_BACK = 60 VOLUME_WRITE_CACHE_POLICY_UPDATE_AUTO = 61 VOLUME_WRITE_CACHE_POLICY_UPDATE_WRITE_THROUGH = 62 VOLUME_WRITE_CACHE_POLICY_UPDATE_IMPACT_READ = 63 VOLUME_WRITE_CACHE_POLICY_UPDATE_WB_IMPACT_OTHER = 64 VOLUME_READ_CACHE_POLICY_UPDATE = 65 VOLUME_READ_CACHE_POLICY_UPDATE_IMPACT_WRITE = 66 # File system FS = 100 FS_DELETE = 101 FS_RESIZE = 102 FS_CREATE = 103 FS_CLONE = 104 FILE_CLONE = 105 FS_SNAPSHOTS = 106 FS_SNAPSHOT_CREATE = 107 FS_SNAPSHOT_DELETE = 109 FS_SNAPSHOT_RESTORE = 110 FS_SNAPSHOT_RESTORE_SPECIFIC_FILES = 111 FS_CHILD_DEPENDENCY = 112 FS_CHILD_DEPENDENCY_RM = 113 FS_CHILD_DEPENDENCY_RM_SPECIFIC_FILES = 114 # NFS EXPORT_AUTH = 120 EXPORTS = 121 EXPORT_FS = 122 EXPORT_REMOVE = 123 EXPORT_CUSTOM_PATH = 124 SYS_READ_CACHE_PCT_UPDATE = 158 SYS_READ_CACHE_PCT_GET = 159 SYS_FW_VERSION_GET = 160 SYS_MODE_GET = 161 DISK_LOCATION = 163 DISK_RPM = 164 DISK_LINK_TYPE = 165 VOLUME_LED = 171 POOLS_QUICK_SEARCH = 210 VOLUMES_QUICK_SEARCH = 211 DISKS_QUICK_SEARCH = 212 ACCESS_GROUPS_QUICK_SEARCH = 213 FS_QUICK_SEARCH = 214 NFS_EXPORTS_QUICK_SEARCH = 215 TARGET_PORTS = 216 TARGET_PORTS_QUICK_SEARCH = 217 DISKS = 220 POOL_MEMBER_INFO = 221 VOLUME_RAID_CREATE = 222 DISK_VPD83_GET = 223 def _to_dict(self): return {'class': self.__class__.__name__, 'cap': ''.join(['%02x' % b for b in self._cap])} def __init__(self, _cap=None): if _cap is not None: self._cap = bytearray(binascii.unhexlify(_cap)) else: self._cap = bytearray(Capabilities._NUM) def supported(self, capability): return self.get(capability) == Capabilities.SUPPORTED def get(self, capability): if capability >= len(self._cap): return Capabilities.UNSUPPORTED return self._cap[capability] @staticmethod def _lsm_cap_to_str_dict(): """ Return a dict containing all valid capability: integer => string name """ lsm_cap_to_str_conv = dict() for c_str, c_int in list(Capabilities.__dict__.items()): if isinstance(c_str, six.string_types) and type(c_int) == int and \ c_str[0] != '_' and \ Capabilities._CAP_NUM_BEGIN <= c_int <= Capabilities._NUM: lsm_cap_to_str_conv[c_int] = c_str return lsm_cap_to_str_conv def get_supported(self, all_cap=False): """ Returns a hash of the supported capabilities in the form constant, name """ all_caps = Capabilities._lsm_cap_to_str_dict() if all_cap: return all_caps rc = {} for i in list(all_caps.keys()): if self._cap[i] == Capabilities.SUPPORTED: if i in all_caps: rc[i] = all_caps[i] return rc def set(self, capability, value=SUPPORTED): self._cap[capability] = value def enable_all(self): for i in range(len(self._cap)): self._cap[i] = Capabilities.SUPPORTED @default_property('id', doc="Unique identifier") @default_property('name', doc="User given name") @default_property('type', doc="Cache hardware type") @default_property('status', doc='Battery status') @default_property('system_id', doc="System identifier") @default_property("plugin_data", doc="Private plugin data") class Battery(IData): SUPPORTED_SEARCH_KEYS = ['id', 'system_id'] TYPE_UNKNOWN = 1 TYPE_OTHER = 2 TYPE_CHEMICAL = 3 TYPE_CAPACITOR = 4 STATUS_UNKNOWN = 1 << 0 STATUS_OTHER = 1 << 1 STATUS_OK = 1 << 2 STATUS_DISCHARGING = 1 << 3 STATUS_CHARGING = 1 << 4 STATUS_LEARNING = 1 << 5 STATUS_DEGRADED = 1 << 6 STATUS_ERROR = 1 << 7 def __init__(self, _id, _name, _type, _status, _system_id, _plugin_data=None): self._id = _id self._name = _name self._type = _type self._status = _status self._system_id = _system_id self._plugin_data = _plugin_data if __name__ == '__main__': # TODO Need some unit tests that encode/decode all the types with nested pass _data.pyc000064400000103475147576505410006361 0ustar00 -P`c@sddlmZddlZddlZddlmZyddlZWne k rgddlZnXddl m Z ddl m Z mZmZmZddlZdejfdYZdejfd YZd eeefd YZed d dedd dedd dedd dedd dedd dedd dedd ddefdYZejdZed d dedd d ed!d d"edd d#edd d$ed%d d&edd ded'd d(edd dd)efd*YZed d dedd d+edd d,ed-d d.edd dd/efd0YZed d dedd d1ed2d d3ed4d d5edd ded-d d6edd dedd d7ed8d d9ed:d d;d<efd=YZed d dedd d>ed2d d3ed4d d?ed'd d@edd dAedd ddBefdCYZed d dedd dDedEd dFedd ddGefdHYZed d dedId dJedKd dLedMd dNedOd dPedQd dRedSd dTedUd dVedWd dXedYd dZedd d[d\efd]YZed^d d_ed`d daedbd d$dcefddYZ ed d deedd dfedgd dhedid djedd dedd d[dkefdlYZ!ed d deedmd dnedod dpedqd dredsd dtedud dvedd dedd d[dwefdxYZ"dyefdzYZ#ed d dedd d ed{d d|edd d}edd dedd dd~efdYZ$e%dkrndS(i(tABCMetaN(twith_metaclass(t WHITESPACE(t get_classtdefault_propertyt ErrorNumbertLsmErrort DataEncodercBseZdZdZRS(s? Custom json encoder for objects derived form ILsmData cCs<t|ts.tdtt|n |jSdS(Nsincorrect class type:(t isinstancetIDatat ValueErrortstrttypet_to_dict(tselftmy_class((s-/usr/lib/python2.7/site-packages/lsm/_data.pytdefault*s(t__name__t __module__t__doc__R(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR%st DataDecodercBsJeZdZedZedZedZejdZ RS(s? Custom json decoder for objects derived from ILsmData cCsXi}d|kr$tj|}n0x-|jD]\}}tj|||tj|S|SdS(s) Decodes the parsed json N(R R"RR#RR!(te((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt__decodeTs   cCstjtj|S(N(RRtjsontloads(Rt json_stringt_w((s-/usr/lib/python2.7/site-packages/lsm/_data.pytdecode`s( RRRt staticmethodR#R!RRtmatchR.(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR1s  R cBs/eZdZdZedZdZRS(s? Base class functionality of serializable classes. cCsqi|jjd6}xWt|jjD]@\}}t|tr[|j||d(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt size_bytesscCs+|jdkr$ttjdn|jS(s String. SCSI VPD83 ID. New in version 1.3. Only available for DAS(direct attached storage) systems. The VPD83 ID could be used in 'lsm.SCSI.disk_paths_of_vpd83()' when physical disk is exposed to OS directly. RCs5Disk.vpd83 is not supported by current disk or plugin(RORRt NO_SUPPORT(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pytvpd83s  cCs+|jdkr$ttjdn|jS(sP String. Disk location in storage topology. New in version 1.3. RCs:Disk.location property is not supported by this plugin yet(RPRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pytlocation&s  cCs.|jtjkr'ttjdn|jS(s Integer. New in version 1.3. Disk rotation speed - revolutions per minute(RPM): -1 (LSM_DISK_RPM_UNKNOWN): Unknown RPM 0 (LSM_DISK_RPM_NON_ROTATING_MEDIUM): Non-rotating medium (e.g., SSD) 1 (LSM_DISK_RPM_ROTATING_UNKNOWN_SPEED): Rotational disk with unknown speed >1: Normal rotational disk (e.g., HDD) s,Disk.rpm is not supported by this plugin yet(RQRBtRPM_NO_SUPPORTRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pytrpm1s  cCs.|jtjkr'ttjdn|jS(s Integer. New in version 1.3. Link type, possible values are: lsm.Disk.LINK_TYPE_UNKNOWN Failed to detect link type lsm.Disk.LINK_TYPE_FC Fibre Channel lsm.Disk.LINK_TYPE_SSA Serial Storage Architecture, Old IBM tech. lsm.Disk.LINK_TYPE_SBP Serial Bus Protocol, used by IEEE 1394. lsm.Disk.LINK_TYPE_SRP SCSI RDMA Protocol lsm.Disk.LINK_TYPE_ISCSI Internet Small Computer System Interface lsm.Disk.LINK_TYPE_SAS Serial Attached SCSI lsm.Disk.LINK_TYPE_ADT Automation/Drive Interface Transport Protocol, often used by Tape. lsm.Disk.LINK_TYPE_ATA PATA/IDE or SATA. lsm.Disk.LINK_TYPE_USB USB disk. lsm.Disk.LINK_TYPE_SOP SCSI over PCI-E lsm.Disk.LINK_TYPE_PCIE PCI-E, e.g. NVMe s2Disk.link_type is not supported by this plugin yet(RRRBtLINK_TYPE_NO_SUPPORTRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt link_typeDs  cCs|jS(N(R;(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR8isiiiiii i@iiiiiii iiiiii i@N(GRRRtSUPPORTED_SEARCH_KEYStBLOCK_COUNT_NOT_FOUNDtBLOCK_SIZE_NOT_FOUNDt TYPE_UNKNOWNt TYPE_OTHERtTYPE_ATAt TYPE_SATAtTYPE_SAStTYPE_FCtTYPE_SOPt TYPE_SCSItTYPE_LUNt TYPE_NL_SAStTYPE_HDDtTYPE_SSDt TYPE_HYBRIDtSTATUS_UNKNOWNt STATUS_OKt STATUS_OTHERtSTATUS_PREDICTIVE_FAILUREt STATUS_ERRORtSTATUS_REMOVEDtSTATUS_STARTINGtSTATUS_STOPPINGtSTATUS_STOPPEDtSTATUS_INITIALIZINGtSTATUS_MAINTENANCE_MODEtSTATUS_SPARE_DISKtSTATUS_RECONSTRUCTt STATUS_FREERXt RPM_UNKNOWNtRPM_NON_ROTATING_MEDIUMtRPM_ROTATING_UNKNOWN_SPEEDRZtLINK_TYPE_UNKNOWNt LINK_TYPE_FCt LINK_TYPE_SSAt LINK_TYPE_SBPt LINK_TYPE_SRPtLINK_TYPE_ISCSIt LINK_TYPE_SASt LINK_TYPE_ADTt LINK_TYPE_ATAt LINK_TYPE_USBt LINK_TYPE_SOPtLINK_TYPE_PCIEtLED_STATUS_UNKNOWNtLED_STATUS_IDENT_ONtLED_STATUS_IDENT_OFFtLED_STATUS_IDENT_UNKNOWNtLED_STATUS_FAULT_ONtLED_STATUS_FAULT_OFFtLED_STATUS_FAULT_UNKNOWNtLINK_SPEED_UNKNOWNtHEALTH_STATUS_UNKNOWNtHEALTH_STATUS_FAILtHEALTH_STATUS_WARNtHEALTH_STATUS_GOODtNoneRStpropertyRTRVRWRYR[R8(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRBs     %s*(?:^6[0-9a-f]{31})|(?:^[235][0-9a-f]{15})$sUser given nameRVs"Vital product page 0x83 identifiersVolume block sizesNumber of blockst admin_states$Enabled or disabled by administratortpool_idsPool identifierRLcBs|eZdZdddgZdZdZdZdZdZdZ d Z dZ dZ d Z d ZdZd Zd ZdZdZdZd Zd Zd ZdZdZdZdZdZdZdZdZd Z d Z!d Z"d Z#d Z$d Z%dZ&dZ'dZ(d Z)dZ*dZ+d Z,dZ-dZ.d Z/dZ0dZ1d Z2dZ3dZ4dZ5ddZ7e8dZ9dZ:e;dZ<RS(s Represents a volume. R9R@Riiiiiiiii iii2i<i3i=iiic Cs||_||_|rAtj| rAttjd|n||_||_||_ ||_ ||_ ||_ | |_ dS(Ns^Incorrect format of VPD 0x83 NAA(3) string: '%s', expecting 32 or 16 lower case hex characters(RDRERLRMRRRNRORGRHt _admin_stateRJt_pool_idRK( RRDRERORGRHRRJRRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs          cCs|j|jS(s' Volume size in bytes. (R=R>(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRTscCs|jS(N(R;(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR8scCs|rtj|rtStS(sI Returns True if string is valid vpd 0x83 representation (t_vol_regex_vpd83R0tTruetFalse(tvpd((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRMsN(=RRRR\tREPLICATE_UNKNOWNtREPLICATE_CLONEtREPLICATE_COPYtREPLICATE_MIRROR_SYNCtREPLICATE_MIRROR_ASYNCtPROVISION_UNKNOWNtPROVISION_THINtPROVISION_FULLtPROVISION_DEFAULTtADMIN_STATE_DISABLEDtADMIN_STATE_ENABLEDtRAID_TYPE_UNKNOWNtRAID_TYPE_RAID0tRAID_TYPE_RAID1tRAID_TYPE_RAID3tRAID_TYPE_RAID4tRAID_TYPE_RAID5tRAID_TYPE_RAID6tRAID_TYPE_RAID10tRAID_TYPE_RAID15tRAID_TYPE_RAID16tRAID_TYPE_RAID50tRAID_TYPE_RAID60tRAID_TYPE_RAID51tRAID_TYPE_RAID61tRAID_TYPE_JBODtRAID_TYPE_MIXEDtRAID_TYPE_OTHERtSTRIP_SIZE_UNKNOWNtDISK_COUNT_UNKNOWNtMIN_IO_SIZE_UNKNOWNtOPT_IO_SIZE_UNKNOWNtVCR_STRIP_SIZE_DEFAULTtWRITE_CACHE_POLICY_UNKNOWNtWRITE_CACHE_POLICY_WRITE_BACKtWRITE_CACHE_POLICY_AUTOt WRITE_CACHE_POLICY_WRITE_THROUGHtWRITE_CACHE_STATUS_UNKNOWNtWRITE_CACHE_STATUS_WRITE_BACKt WRITE_CACHE_STATUS_WRITE_THROUGHtREAD_CACHE_POLICY_UNKNOWNtREAD_CACHE_POLICY_ENABLEDtREAD_CACHE_POLICY_DISABLEDtREAD_CACHE_STATUS_UNKNOWNtREAD_CACHE_STATUS_ENABLEDtREAD_CACHE_STATUS_DISABLEDtPHYSICAL_DISK_CACHE_UNKNOWNtPHYSICAL_DISK_CACHE_ENABLEDtPHYSICAL_DISK_CACHE_DISABLEDt$PHYSICAL_DISK_CACHE_USE_DISK_SETTINGRRSRRTR8R/RM(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRLrsp   sUser defined system namesEnumerated status of systemt status_infos#Detail status information of systemtSystemcBseZd ZdZdZdZdZdZdZdZ dZ dZ dZ dZ ddddd Zed Zed Zed ZRS(iiiiiiiiRCc Cs||_||_||_||_||_||_|dkrQtj|_ n ||_ |dkrutj |_ n ||_ dS(N( RDRERIt _status_infoRKt _fw_versionRRtREAD_CACHE_PCT_NO_SUPPORTt_read_cache_pcttMODE_NO_SUPPORTt_mode( RRDRERIRRKRRR((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRS s         cCs+|jdkr$ttjdn|jS(s String. Firmware version string. New in version 1.3. On some system, it might contain multiple version strings, example: "Package: 23.32.0-0009, FW: 3.440.05-3712" RCs7System.fw_version() is not supported by this plugin yet(RRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt fw_versions  cCs.|jtjkr'ttjdn|jS(sQ Integer(enumerated value). System mode. New in version 1.3. Only available for HW RAID systems at this time. Possible values: * lsm.System.MODE_HARDWARE_RAID The logical volume(aka, RAIDed virtual disk) can be exposed to OS while hardware RAID card is handling the RAID algorithm. Physical disk can not be exposed to OS directly. * lsm.System.MODE_HBA The physical disks can be exposed to OS directly. SCSI enclosure service might be exposed to OS also. s/System.mode is not supported by this plugin yet(RRRRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pytmode)s  cCs.|jtjkr'ttjdn|jS(s Integer. Read cache percentage. New in version 1.3. Possible values: * 0-100 The read cache percentage. The write cache percentage will then be 100 - read_cache_pct s9System.read_cache_pct is not supported by this plugin yet(RRRRRRU(R((s-/usr/lib/python2.7/site-packages/lsm/_data.pytread_cache_pct=s   iiiiii N(RRRlRmRptSTATUS_DEGRADEDRoRnRt MODE_UNKNOWNtMODE_HARDWARE_RAIDtMODE_HBARtREAD_CACHE_PCT_UNKNOWNRRSRRRR(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRs" sUser supplied namet total_spacesTotal space in bytest free_spacesFree space in bytessText explaining statussPlug-in private datat element_typesWhat pool can be used fortunsupported_actionss"What cannot be done with this pooltPoolcBseZdZddgZdZdZdZdZdZdZ dZ dZ dZ dZ dZdZdZdZdZdZd Zd!Zd"Zd#Zd$Zd ZdZdZdZd%dZRS(&s# Pool specific information R9R@iiiiiiii ii i i iic Cs^||_||_||_||_||_||_||_||_| |_| |_ dS(N( RDREt _element_typet_unsupported_actionst _total_spacet _free_spaceRIRRJRK( RRDRERRRRRIRRJRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs         iiiii i@iiiiiiii iii i@iN(RRRR\tTOTAL_SPACE_NOT_FOUNDtFREE_SPACE_NOT_FOUNDtELEMENT_TYPE_POOLtELEMENT_TYPE_VOLUMEtELEMENT_TYPE_FStELEMENT_TYPE_DELTAtELEMENT_TYPE_VOLUME_FULLtELEMENT_TYPE_VOLUME_THINtELEMENT_TYPE_SYS_RESERVEDtUNSUPPORTED_VOLUME_GROWtUNSUPPORTED_VOLUME_SHRINKRlRmRnRRpRttSTATUS_RECONSTRUCTINGtSTATUS_VERIFYINGRutSTATUS_GROWINGtMEMBER_TYPE_UNKNOWNtMEMBER_TYPE_OTHERtMEMBER_TYPE_DISKtMEMBER_TYPE_POOLRRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRMs8 sFile system namesFree space availables$What pool the file system resides ons System IDt FileSystemcBs#eZdddgZddZRS(R9R@RcCsC||_||_||_||_||_||_||_dS(N(RDRERRRRJRK(RRDRERRRRJRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs      N(RRR\RRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRss Snapshot namettss#Time stamp the snapshot was createdt FsSnapshotcBseZddZRS(cCs.||_||_t||_||_dS(N(RDREtintt_tsRK(RRDRERRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs  N(RRRRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRstfs_idsFilesystem that is exportedt export_paths Export pathtauthsAuthentication typetroots!List of hosts with no_root_squashtrws*List of hosts with Read & Write privilegestros'List of hosts with Read only privilegestanonuidsUID for anonymous user idtanongidsGID for anonymous group idtoptionss"String containing advanced optionssPlugin private datat NfsExportcBs,eZddgZdZdZddZRS(R9Riic Cs|dk st|dk s$t||_||_||_||_||_||_||_||_ | |_ | |_ | |_ dS(N( RtAssertionErrorRDt_fs_idt _export_patht_autht_roott_rwt_rot_anonuidt_anongidt_optionsRK( RRDR R RRRRRRRRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs          N(RRR\tANON_UID_GID_NAtANON_UID_GID_ERRORRRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR s t src_blocksSource logical block addresst dest_blocks!Destination logical block addresst block_countt BlockRangecBseZdZRS(cCs||_||_||_dS(N(t _src_blockt _dest_blockt _block_count(RRRR((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs  (RRRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRssUnique instance identifiersAccess group nametinit_idssList of initiator IDst init_typesInitiator typet AccessGroupcBseZddgZdZdZdZdZdZd dZ e dZ e j d e jZe d ed Ze ed ZRS( R9R@iiiiicCsC||_||_tj||_||_||_||_dS(N(RDRER t_standardize_init_listt _init_idst _init_typeRJRK(RRDRER"R#RJRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs     cCs_g}xR|D]J}tj|\}}}|rA|j|q ttjd|q W|S(NsInvalid initiator ID %s(R tinitiator_id_verifyR RRRN(RRtitvalidRtinit_id((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR!s  sR ^(0x|0X)?([0-9A-Fa-f]{2}) (([\.:\-])?[0-9A-Fa-f]{2}){7}$ cCs|jds-|jds-|jdr[|dksH|tjkr[ttj|fSntjjt|r|dks|tjkrttjtj |fSn|rt t j d|nt ddfS(s Public method which can be used to verify an initiator id :param init_id: :param init_type: :param raise_exception: Will throw a LsmError INVALID_ARGUMENT if not a valid initiator address :return:(Bool, init_type, init_id) Note: init_id will be returned in normalized format if it's a WWPN tiqnteuitnaasInitiator id '%s' is invalidN(t startswithRR tINIT_TYPE_ISCSI_IQNRt _regex_wwpnR0R tINIT_TYPE_WWPNt_wwpn_to_lsm_typeRRRNR(R'Rtraise_exception((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR$s     cCstjjt|ryt|}|j}tjdd|}tjdd|}djtjd|}|S|rt t j d|ndS(s Convert provided WWPN string into LSM standard one: LSM WWPN format: ^(?:[0-9a-f]{2}:){7}[0-9a-f]{2}$ LSM WWPN Example: 10:00:00:00:c9:95:2f:de Acceptable WWPN format is: ^[0x|0X]{0,1}(:?[0-9A-Fa-f]{2}[\.\-:]{0,1}){7}[0-9A-Fa-f]{2}$ Acceptable WWPN example: 10:00:00:00:c9:95:2f:de 10:00:00:00:C9:95:2F:DE 10-00-00-00-C9-95-2F-DE 10-00-00-00-c9-95-2f-de 10.00.00.00.C9.95.2F.DE 10.00.00.00.c9.95.2f.de 0x10000000c9952fde 0X10000000C9952FDE 10000000c9952fde 10000000C9952FDE Return the LSM WWPN Return None if raise_error is False and not a valid WWPN. t0xRCs [^0-9a-f]t:s..sInvalid WWPN Initiator: %sN( R R-R0R tlowertretsubtjointfindallRRRNR(twwpnt raise_errorts((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR/+s   N(RRR\tINIT_TYPE_UNKNOWNtINIT_TYPE_OTHERR.R,tINIT_TYPE_ISCSI_WWPN_MIXEDRRSR/R!R4tcompiletXR-RR$RR/(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR s   t port_typesTarget port typetservice_addresssTarget port service addresstnetwork_addresssTarget port network addresstphysical_addresssTarget port physical addresst physical_namesTarget port physical port namet TargetPortcBs8eZddgZdZdZdZdZddZRS(R9R@iiiic CsL||_||_||_||_||_||_||_||_dS(N(RDt _port_typet_service_addresst_network_addresst_physical_addresst_physical_nameRJRK( RRDRFRGRHRIRJRJRK((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSbs       N( RRR\R`Rdt TYPE_FCOEt TYPE_ISCSIRRS(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRERs  t CapabilitiescBs]eZdZdZdZdZdZdZdZdZ dZ dZ d Z d Z d Zd Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"d Z#d!Z$d"Z%d#Z&d$Z'd%Z(d&Z)d'Z*d(Z+d)Z,d*Z-d+Z.d,Z/d-Z0d.Z1d/Z2d0Z3d1Z4d2Z5d3Z6d4Z7d5Z8d6Z9d7Z:d8Z;d9Z<d:Z=d;Z>d<Z?d=Z@d>ZAd?ZBd@ZCdAZDdBZEdCZFdDZGdEZHdFZIdGZJdHZKdIZLdJZMdKZNdLZOdMZPdNZQdOZRdPZSdQZTdRZUdSZVdTZWd\dUZYdVZZdWZ[e\dXZ]e^dYZ_edZZ`d[ZaRS(]iiiiiiiiiiiiiiii!i"i#i$i%i&i'i(i)i*i+i,i-i.i/i0i5i6i7i8i9i:i;i<i=i>i?i@iAiBidieifigihiiijikiminioipiqirixiyizi{i|iiiiiiiiiiiiiiiiiiiicCs;i|jjd6djg|jD]}d|^q d6S(NRRCs%02xtcap(R1RR6t_cap(Rtb((s-/usr/lib/python2.7/site-packages/lsm/_data.pyR scCs=|dk r'ttj||_nttj|_dS(N(Rt bytearraytbinasciit unhexlifyRORMt_NUM(RRO((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRSs cCs|j|tjkS(N(tgetRMt SUPPORTED(Rt capability((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt supportedscCs'|t|jkrtjS|j|S(N(tlenRORMt UNSUPPORTED(RRW((s-/usr/lib/python2.7/site-packages/lsm/_data.pyRUscCst}xttjjD]o\}}t|tjrt|t kr|ddkrtj |ko|tj knr||| string name iR4( R"RRMR2RRtsixt string_typesR Rt_CAP_NUM_BEGINRT(tlsm_cap_to_str_convtc_strtc_int((s-/usr/lib/python2.7/site-packages/lsm/_data.pyt_lsm_cap_to_str_dicts "$"cCsstj}|r|Si}xPt|jD]<}|j|tjkr/||krk||||RRLRRRRR RR RERMRR(((s-/usr/lib/python2.7/site-packages/lsm/_data.pyts   "  31+.{"R  1<( 4%j+*% plugin/__init__.py000064400000000000147576505410010157 0ustar00plugin/__init__.pyc000064400000000216147576505410010333 0ustar00 /P`c@sdS(N((((s7/usr/lib/python2.7/site-packages/lsm/plugin/__init__.pytsplugin/__init__.pyo000064400000000216147576505410010347 0ustar00 /P`c@sdS(N((((s7/usr/lib/python2.7/site-packages/lsm/plugin/__init__.pytsplugin/sim/__init__.py000064400000000000147576505410010747 0ustar00plugin/sim/simulator.py000064400000034017147576505410011246 0ustar00# Copyright (C) 2011-2016 Red Hat, Inc. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: tasleson # Gris Ge from lsm import (uri_parse, VERSION, Capabilities, INfs, IStorageAreaNetwork, search_property, Client, LsmError, ErrorNumber) from lsm.plugin.sim.simarray import SimArray class SimPlugin(INfs, IStorageAreaNetwork): """ Simple class that implements enough to allow the framework to be exercised. """ def __init__(self): self.uri = None self.password = None self.sim_array = None def plugin_register(self, uri, password, timeout, flags=0): self.uri = uri self.password = password # The caller may want to start clean, so we allow the caller to specify # a file to store and retrieve individual state. qp = uri_parse(uri) if 'parameters' in qp and 'statefile' in qp['parameters'] \ and qp['parameters']['statefile'] is not None: self.sim_array = SimArray(qp['parameters']['statefile'], timeout) else: self.sim_array = SimArray(None, timeout) return None def plugin_unregister(self, flags=0): pass def job_status(self, job_id, flags=0): return self.sim_array.job_status(job_id, flags) def job_free(self, job_id, flags=0): return self.sim_array.job_free(job_id, flags) @staticmethod def _sim_data_2_lsm(sim_data): """ Fake converter. SimArray already do SimData to LSM data convert. We move data convert to SimArray to make this sample plugin looks clean. But in real world, data converting is often handled by plugin itself rather than array. """ return sim_data def time_out_set(self, ms, flags=0): self.sim_array.time_out_set(ms, flags) return None def time_out_get(self, flags=0): return self.sim_array.time_out_get(flags) def capabilities(self, system, flags=0): rc = Capabilities() rc.enable_all() rc.set(Capabilities.POOLS_QUICK_SEARCH, Capabilities.UNSUPPORTED) rc.set(Capabilities.VOLUMES_QUICK_SEARCH, Capabilities.UNSUPPORTED) rc.set(Capabilities.DISKS_QUICK_SEARCH, Capabilities.UNSUPPORTED) rc.set(Capabilities.FS_QUICK_SEARCH, Capabilities.UNSUPPORTED) rc.set(Capabilities.ACCESS_GROUPS_QUICK_SEARCH, Capabilities.UNSUPPORTED) rc.set(Capabilities.NFS_EXPORTS_QUICK_SEARCH, Capabilities.UNSUPPORTED) rc.set(Capabilities.TARGET_PORTS_QUICK_SEARCH, Capabilities.UNSUPPORTED) rc.set(Capabilities.VOLUME_PHYSICAL_DISK_CACHE_UPDATE_SYSTEM_LEVEL, Capabilities.UNSUPPORTED) rc.set(Capabilities.VOLUME_WRITE_CACHE_POLICY_UPDATE_IMPACT_READ, Capabilities.UNSUPPORTED) rc.set(Capabilities.VOLUME_WRITE_CACHE_POLICY_UPDATE_WB_IMPACT_OTHER, Capabilities.UNSUPPORTED) rc.set(Capabilities.VOLUME_READ_CACHE_POLICY_UPDATE_IMPACT_WRITE, Capabilities.UNSUPPORTED) return rc def plugin_info(self, flags=0): return "Storage simulator", VERSION def systems(self, flags=0): sim_syss = self.sim_array.systems() return [SimPlugin._sim_data_2_lsm(s) for s in sim_syss] def system_read_cache_pct_update(self, system, read_pct, flags=0): return self.sim_array.system_read_cache_pct_update(system, read_pct) def pools(self, search_key=None, search_value=None, flags=0): sim_pools = self.sim_array.pools(flags) return search_property( [SimPlugin._sim_data_2_lsm(p) for p in sim_pools], search_key, search_value) def volumes(self, search_key=None, search_value=None, flags=0): sim_vols = self.sim_array.volumes() return search_property( [SimPlugin._sim_data_2_lsm(v) for v in sim_vols], search_key, search_value) def disks(self, search_key=None, search_value=None, flags=0): sim_disks = self.sim_array.disks() return search_property( [SimPlugin._sim_data_2_lsm(d) for d in sim_disks], search_key, search_value) def volume_create(self, pool, volume_name, size_bytes, provisioning, flags=0): sim_vol = self.sim_array.volume_create( pool.id, volume_name, size_bytes, provisioning, flags) return SimPlugin._sim_data_2_lsm(sim_vol) def volume_delete(self, volume, flags=0): return self.sim_array.volume_delete(volume.id, flags) def volume_resize(self, volume, new_size_bytes, flags=0): sim_vol = self.sim_array.volume_resize( volume.id, new_size_bytes, flags) return SimPlugin._sim_data_2_lsm(sim_vol) def volume_replicate(self, pool, rep_type, volume_src, name, flags=0): if pool is not None: dst_pool_id = pool.id else: dst_pool_id = volume_src.pool_id return self.sim_array.volume_replicate( dst_pool_id, rep_type, volume_src.id, name, flags) def volume_replicate_range_block_size(self, system, flags=0): return self.sim_array.volume_replicate_range_block_size( system.id, flags) def volume_replicate_range(self, rep_type, volume_src, volume_dest, ranges, flags=0): return self.sim_array.volume_replicate_range( rep_type, volume_src.id, volume_dest.id, ranges, flags) def volume_enable(self, volume, flags=0): return self.sim_array.volume_enable(volume.id, flags) def volume_disable(self, volume, flags=0): return self.sim_array.volume_disable(volume.id, flags) def access_groups(self, search_key=None, search_value=None, flags=0): sim_ags = self.sim_array.ags() return search_property( [SimPlugin._sim_data_2_lsm(a) for a in sim_ags], search_key, search_value) def access_group_create(self, name, init_id, init_type, system, flags=0): sim_ag = self.sim_array.access_group_create( name, init_id, init_type, system.id, flags) return SimPlugin._sim_data_2_lsm(sim_ag) def access_group_delete(self, access_group, flags=0): return self.sim_array.access_group_delete(access_group.id, flags) def access_group_initiator_add(self, access_group, init_id, init_type, flags=0): sim_ag = self.sim_array.access_group_initiator_add( access_group.id, init_id, init_type, flags) return SimPlugin._sim_data_2_lsm(sim_ag) def access_group_initiator_delete(self, access_group, init_id, init_type, flags=0): sim_ag = self.sim_array.access_group_initiator_delete( access_group.id, init_id, init_type, flags) return SimPlugin._sim_data_2_lsm(sim_ag) def volume_mask(self, access_group, volume, flags=0): return self.sim_array.volume_mask( access_group.id, volume.id, flags) def volume_unmask(self, access_group, volume, flags=0): return self.sim_array.volume_unmask( access_group.id, volume.id, flags) def volumes_accessible_by_access_group(self, access_group, flags=0): sim_vols = self.sim_array.volumes_accessible_by_access_group( access_group.id, flags) return [SimPlugin._sim_data_2_lsm(v) for v in sim_vols] def access_groups_granted_to_volume(self, volume, flags=0): sim_vols = self.sim_array.access_groups_granted_to_volume( volume.id, flags) return [SimPlugin._sim_data_2_lsm(v) for v in sim_vols] def iscsi_chap_auth(self, init_id, in_user, in_password, out_user, out_password, flags=0): if out_user and out_password and \ (in_user is None or in_password is None): raise LsmError(ErrorNumber.INVALID_ARGUMENT, "out_user and out_password only supported if " "inbound is supplied") return self.sim_array.iscsi_chap_auth( init_id, in_user, in_password, out_user, out_password, flags) def volume_child_dependency(self, volume, flags=0): return self.sim_array.volume_child_dependency(volume.id, flags) def volume_child_dependency_rm(self, volume, flags=0): return self.sim_array.volume_child_dependency_rm(volume.id, flags) def fs(self, search_key=None, search_value=None, flags=0): sim_fss = self.sim_array.fs() return search_property( [SimPlugin._sim_data_2_lsm(f) for f in sim_fss], search_key, search_value) def fs_create(self, pool, name, size_bytes, flags=0): sim_fs = self.sim_array.fs_create(pool.id, name, size_bytes) return SimPlugin._sim_data_2_lsm(sim_fs) def fs_delete(self, fs, flags=0): return self.sim_array.fs_delete(fs.id, flags) def fs_resize(self, fs, new_size_bytes, flags=0): sim_fs = self.sim_array.fs_resize( fs.id, new_size_bytes, flags) return SimPlugin._sim_data_2_lsm(sim_fs) def fs_clone(self, src_fs, dest_fs_name, snapshot=None, flags=0): if snapshot is None: return self.sim_array.fs_clone( src_fs.id, dest_fs_name, None, flags) return self.sim_array.fs_clone( src_fs.id, dest_fs_name, snapshot.id, flags) def fs_file_clone(self, fs, src_file_name, dest_file_name, snapshot=None, flags=0): if snapshot is None: return self.sim_array.fs_file_clone( fs.id, src_file_name, dest_file_name, None, flags) return self.sim_array.fs_file_clone( fs.id, src_file_name, dest_file_name, snapshot.id, flags) def fs_snapshots(self, fs, flags=0): sim_snaps = self.sim_array.fs_snapshots(fs.id, flags) return [SimPlugin._sim_data_2_lsm(s) for s in sim_snaps] def fs_snapshot_create(self, fs, snapshot_name, flags=0): return self.sim_array.fs_snapshot_create( fs.id, snapshot_name, flags) def fs_snapshot_delete(self, fs, snapshot, flags=0): return self.sim_array.fs_snapshot_delete( fs.id, snapshot.id, flags) def fs_snapshot_restore(self, fs, snapshot, files, restore_files, all_files=False, flags=0): return self.sim_array.fs_snapshot_restore( fs.id, snapshot.id, files, restore_files, all_files, flags) def fs_child_dependency(self, fs, files, flags=0): return self.sim_array.fs_child_dependency(fs.id, files, flags) def fs_child_dependency_rm(self, fs, files, flags=0): return self.sim_array.fs_child_dependency_rm(fs.id, files, flags) def export_auth(self, flags=0): # The API should change some day return ["standard"] def exports(self, search_key=None, search_value=None, flags=0): sim_exps = self.sim_array.exports(flags) return search_property( [SimPlugin._sim_data_2_lsm(e) for e in sim_exps], search_key, search_value) def export_fs(self, fs_id, export_path, root_list, rw_list, ro_list, anon_uid, anon_gid, auth_type, options, flags=0): sim_exp = self.sim_array.fs_export( fs_id, export_path, root_list, rw_list, ro_list, anon_uid, anon_gid, auth_type, options, flags=0) return SimPlugin._sim_data_2_lsm(sim_exp) def export_remove(self, export, flags=0): return self.sim_array.fs_unexport(export.id, flags) def target_ports(self, search_key=None, search_value=None, flags=0): sim_tgts = self.sim_array.target_ports() return search_property( [SimPlugin._sim_data_2_lsm(t) for t in sim_tgts], search_key, search_value) def volume_raid_info(self, volume, flags=0): return self.sim_array.volume_raid_info(volume) def pool_member_info(self, pool, flags=0): return self.sim_array.pool_member_info(pool) def volume_raid_create_cap_get(self, system, flags=0): return self.sim_array.volume_raid_create_cap_get(system) def volume_raid_create(self, name, raid_type, disks, strip_size, flags=0): return self.sim_array.volume_raid_create( name, raid_type, disks, strip_size) def volume_ident_led_on(self, volume, flags=0): return self.sim_array.volume_ident_led_on(volume) def volume_ident_led_off(self, volume, flags=0): return self.sim_array.volume_ident_led_off(volume) def batteries(self, search_key=None, search_value=None, flags=Client.FLAG_RSVD): sim_batteries = self.sim_array.batteries() return search_property( [SimPlugin._sim_data_2_lsm(b) for b in sim_batteries], search_key, search_value) def volume_cache_info(self, volume, flags=Client.FLAG_RSVD): return self.sim_array.volume_cache_info(volume) def volume_physical_disk_cache_update(self, volume, pdc, flags=Client.FLAG_RSVD): return self.sim_array.volume_physical_disk_cache_update(volume, pdc) def volume_read_cache_policy_update(self, volume, rcp, flags=Client.FLAG_RSVD): return self.sim_array.volume_read_cache_policy_update(volume, rcp) def volume_write_cache_policy_update(self, volume, wcp, flags=Client.FLAG_RSVD): return self.sim_array.volume_write_cache_policy_update(volume, wcp) plugin/sim/simulator.pyc000064400000042756147576505410011422 0ustar00 .P`c@smddlmZmZmZmZmZmZmZmZm Z ddl m Z deefdYZ dS(i( t uri_parsetVERSIONt CapabilitiestINfstIStorageAreaNetworktsearch_propertytClienttLsmErrort ErrorNumber(tSimArrayt SimPlugincBsJeZdZdZddZddZddZddZedZ ddZ dd Z dd Z dd Z dd Zdd ZdAdAddZdAdAddZdAdAddZddZddZddZddZddZddZddZddZdAdAddZddZddZddZddZ ddZ!ddZ"dd Z#dd!Z$dd"Z%dd#Z&dd$Z'dAdAdd%Z(dd&Z)dd'Z*dd(Z+dAdd)Z,dAdd*Z-dd+Z.dd,Z/dd-Z0e1dd.Z2dd/Z3dd0Z4dd1Z5dAdAdd2Z6dd3Z7dd4Z8dAdAdd5Z9dd6Z:dd7Z;dd8Z<dd9Z=dd:Z>dd;Z?dAdAe@jAd<ZBe@jAd=ZCe@jAd>ZDe@jAd?ZEe@jAd@ZFRS(BsU Simple class that implements enough to allow the framework to be exercised. cCsd|_d|_d|_dS(N(tNoneturitpasswordt sim_array(tself((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt__init__s  icCs||_||_t|}d|krkd|dkrk|dddk rkt|dd||_ntd||_dS(Nt parameterst statefile(R R RR R R(RR R ttimeouttflagstqp((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pytplugin_register"s   cCsdS(N((RR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pytplugin_unregister1scCs|jj||S(N(Rt job_status(Rtjob_idR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR4scCs|jj||S(N(Rtjob_free(RRR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR7scCs|S(s Fake converter. SimArray already do SimData to LSM data convert. We move data convert to SimArray to make this sample plugin looks clean. But in real world, data converting is often handled by plugin itself rather than array. ((tsim_data((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt_sim_data_2_lsm:s cCs|jj||dS(N(Rt time_out_setR (RtmsR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyREscCs|jj|S(N(Rt time_out_get(RR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRIscCs t}|j|jtjtj|jtjtj|jtjtj|jtjtj|jtjtj|jtj tj|jtj tj|jtj tj|jtj tj|jtj tj|jtjtj|S(N(Rt enable_alltsettPOOLS_QUICK_SEARCHt UNSUPPORTEDtVOLUMES_QUICK_SEARCHtDISKS_QUICK_SEARCHtFS_QUICK_SEARCHtACCESS_GROUPS_QUICK_SEARCHtNFS_EXPORTS_QUICK_SEARCHtTARGET_PORTS_QUICK_SEARCHt.VOLUME_PHYSICAL_DISK_CACHE_UPDATE_SYSTEM_LEVELt,VOLUME_WRITE_CACHE_POLICY_UPDATE_IMPACT_READt0VOLUME_WRITE_CACHE_POLICY_UPDATE_WB_IMPACT_OTHERt,VOLUME_READ_CACHE_POLICY_UPDATE_IMPACT_WRITE(RtsystemRtrc((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt capabilitiesLs(              cCs dtfS(NsStorage simulator(R(RR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt plugin_infobscCs/|jj}g|D]}tj|^qS(N(RtsystemsR R(RRtsim_syssts((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR2escCs|jj||S(N(Rtsystem_read_cache_pct_update(RR.tread_pctR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR5iscCs>|jj|}tg|D]}tj|^q||S(N(RtpoolsRR R(Rt search_keyt search_valueRt sim_poolstp((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR7lscCs;|jj}tg|D]}tj|^q||S(N(RtvolumesRR R(RR8R9Rtsim_volstv((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR<rscCs;|jj}tg|D]}tj|^q||S(N(RtdisksRR R(RR8R9Rt sim_diskstd((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR?xscCs.|jj|j||||}tj|S(N(Rt volume_createtidR R(Rtpoolt volume_namet size_bytest provisioningRtsim_vol((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRB~s cCs|jj|j|S(N(Rt volume_deleteRC(RtvolumeR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRIscCs(|jj|j||}tj|S(N(Rt volume_resizeRCR R(RRJtnew_size_bytesRRH((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRKs cCs@|dk r|j}n |j}|jj|||j||S(N(R RCtpool_idRtvolume_replicate(RRDtrep_typet volume_srctnameRt dst_pool_id((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRNs     cCs|jj|j|S(N(Rt!volume_replicate_range_block_sizeRC(RR.R((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRSs cCs"|jj||j|j||S(N(Rtvolume_replicate_rangeRC(RRORPt volume_desttrangesR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRTs cCs|jj|j|S(N(Rt volume_enableRC(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRWscCs|jj|j|S(N(Rtvolume_disableRC(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRXscCs;|jj}tg|D]}tj|^q||S(N(RtagsRR R(RR8R9Rtsim_agsta((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt access_groupsscCs.|jj||||j|}tj|S(N(Rtaccess_group_createRCR R(RRQtinit_idt init_typeR.Rtsim_ag((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR]s cCs|jj|j|S(N(Rtaccess_group_deleteRC(Rt access_groupR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRascCs+|jj|j|||}tj|S(N(Rtaccess_group_initiator_addRCR R(RRbR^R_RR`((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRcs cCs+|jj|j|||}tj|S(N(Rtaccess_group_initiator_deleteRCR R(RRbR^R_RR`((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRds cCs|jj|j|j|S(N(Rt volume_maskRC(RRbRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRes cCs|jj|j|j|S(N(Rt volume_unmaskRC(RRbRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRfs cCs8|jj|j|}g|D]}tj|^qS(N(Rt"volumes_accessible_by_access_groupRCR R(RRbRR=R>((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRgs cCs8|jj|j|}g|D]}tj|^qS(N(Rtaccess_groups_granted_to_volumeRCR R(RRJRR=R>((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRhs c CsX|r9|r9|dks$|dkr9ttjdn|jj||||||S(Ns?out_user and out_password only supported if inbound is supplied(R RRtINVALID_ARGUMENTRtiscsi_chap_auth(RR^tin_usert in_passwordtout_usert out_passwordR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRjs     cCs|jj|j|S(N(Rtvolume_child_dependencyRC(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRoscCs|jj|j|S(N(Rtvolume_child_dependency_rmRC(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRpscCs;|jj}tg|D]}tj|^q||S(N(RtfsRR R(RR8R9Rtsim_fsstf((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRqscCs(|jj|j||}tj|S(N(Rt fs_createRCR R(RRDRQRFRtsim_fs((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRtscCs|jj|j|S(N(Rt fs_deleteRC(RRqR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRvscCs(|jj|j||}tj|S(N(Rt fs_resizeRCR R(RRqRLRRu((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRws cCsG|dkr(|jj|j|d|S|jj|j||j|S(N(R Rtfs_cloneRC(Rtsrc_fst dest_fs_nametsnapshotR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRxs    cCsM|dkr+|jj|j||d|S|jj|j|||j|S(N(R Rt fs_file_cloneRC(RRqt src_file_nametdest_file_nameR{R((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR|s    cCs8|jj|j|}g|D]}tj|^qS(N(Rt fs_snapshotsRCR R(RRqRt sim_snapsR4((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRscCs|jj|j||S(N(Rtfs_snapshot_createRC(RRqt snapshot_nameR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRs cCs|jj|j|j|S(N(Rtfs_snapshot_deleteRC(RRqR{R((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR s cCs%|jj|j|j||||S(N(Rtfs_snapshot_restoreRC(RRqR{tfilest restore_filest all_filesR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRs cCs|jj|j||S(N(Rtfs_child_dependencyRC(RRqRR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRscCs|jj|j||S(N(Rtfs_child_dependency_rmRC(RRqRR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRscCsdgS(Ntstandard((RR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt export_authscCs>|jj|}tg|D]}tj|^q||S(N(RtexportsRR R(RR8R9Rtsim_expste((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRsc Cs=|jj||||||||| dd } tj| S(NRi(Rt fs_exportR R( Rtfs_idt export_patht root_listtrw_listtro_listtanon_uidtanon_gidt auth_typetoptionsRtsim_exp((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt export_fs#s cCs|jj|j|S(N(Rt fs_unexportRC(RtexportR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt export_remove*scCs;|jj}tg|D]}tj|^q||S(N(Rt target_portsRR R(RR8R9Rtsim_tgtstt((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR-scCs|jj|S(N(Rtvolume_raid_info(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR3scCs|jj|S(N(Rtpool_member_info(RRDR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR6scCs|jj|S(N(Rtvolume_raid_create_cap_get(RR.R((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR9scCs|jj||||S(N(Rtvolume_raid_create(RRQt raid_typeR?t strip_sizeR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR<s cCs|jj|S(N(Rtvolume_ident_led_on(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRAscCs|jj|S(N(Rtvolume_ident_led_off(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRDscCs;|jj}tg|D]}tj|^q||S(N(Rt batteriesRR R(RR8R9Rt sim_batteriestb((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRGscCs|jj|S(N(Rtvolume_cache_info(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRNscCs|jj||S(N(Rt!volume_physical_disk_cache_update(RRJtpdcR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRQscCs|jj||S(N(Rtvolume_read_cache_policy_update(RRJtrcpR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRUscCs|jj||S(N(Rt volume_write_cache_policy_update(RRJtwcpR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRYsN(Gt__name__t __module__t__doc__RRRRRt staticmethodRRRR0R1R2R5R R7R<R?RBRIRKRNRSRTRWRXR\R]RaRcRdReRfRgRhRjRoRpRqRtRvRwRxR|RRRtFalseRRRRRRRRRRRRRRRt FLAG_RSVDRRRRR(((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR s                                               N( tlsmRRRRRRRRRtlsm.plugin.sim.simarrayR R (((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyts@plugin/sim/simulator.pyo000064400000042756147576505410011436 0ustar00 .P`c@smddlmZmZmZmZmZmZmZmZm Z ddl m Z deefdYZ dS(i( t uri_parsetVERSIONt CapabilitiestINfstIStorageAreaNetworktsearch_propertytClienttLsmErrort ErrorNumber(tSimArrayt SimPlugincBsJeZdZdZddZddZddZddZedZ ddZ dd Z dd Z dd Z dd Zdd ZdAdAddZdAdAddZdAdAddZddZddZddZddZddZddZddZddZdAdAddZddZddZddZddZ ddZ!ddZ"dd Z#dd!Z$dd"Z%dd#Z&dd$Z'dAdAdd%Z(dd&Z)dd'Z*dd(Z+dAdd)Z,dAdd*Z-dd+Z.dd,Z/dd-Z0e1dd.Z2dd/Z3dd0Z4dd1Z5dAdAdd2Z6dd3Z7dd4Z8dAdAdd5Z9dd6Z:dd7Z;dd8Z<dd9Z=dd:Z>dd;Z?dAdAe@jAd<ZBe@jAd=ZCe@jAd>ZDe@jAd?ZEe@jAd@ZFRS(BsU Simple class that implements enough to allow the framework to be exercised. cCsd|_d|_d|_dS(N(tNoneturitpasswordt sim_array(tself((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt__init__s  icCs||_||_t|}d|krkd|dkrk|dddk rkt|dd||_ntd||_dS(Nt parameterst statefile(R R RR R R(RR R ttimeouttflagstqp((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pytplugin_register"s   cCsdS(N((RR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pytplugin_unregister1scCs|jj||S(N(Rt job_status(Rtjob_idR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR4scCs|jj||S(N(Rtjob_free(RRR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR7scCs|S(s Fake converter. SimArray already do SimData to LSM data convert. We move data convert to SimArray to make this sample plugin looks clean. But in real world, data converting is often handled by plugin itself rather than array. ((tsim_data((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt_sim_data_2_lsm:s cCs|jj||dS(N(Rt time_out_setR (RtmsR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyREscCs|jj|S(N(Rt time_out_get(RR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRIscCs t}|j|jtjtj|jtjtj|jtjtj|jtjtj|jtjtj|jtj tj|jtj tj|jtj tj|jtj tj|jtj tj|jtjtj|S(N(Rt enable_alltsettPOOLS_QUICK_SEARCHt UNSUPPORTEDtVOLUMES_QUICK_SEARCHtDISKS_QUICK_SEARCHtFS_QUICK_SEARCHtACCESS_GROUPS_QUICK_SEARCHtNFS_EXPORTS_QUICK_SEARCHtTARGET_PORTS_QUICK_SEARCHt.VOLUME_PHYSICAL_DISK_CACHE_UPDATE_SYSTEM_LEVELt,VOLUME_WRITE_CACHE_POLICY_UPDATE_IMPACT_READt0VOLUME_WRITE_CACHE_POLICY_UPDATE_WB_IMPACT_OTHERt,VOLUME_READ_CACHE_POLICY_UPDATE_IMPACT_WRITE(RtsystemRtrc((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt capabilitiesLs(              cCs dtfS(NsStorage simulator(R(RR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt plugin_infobscCs/|jj}g|D]}tj|^qS(N(RtsystemsR R(RRtsim_syssts((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR2escCs|jj||S(N(Rtsystem_read_cache_pct_update(RR.tread_pctR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR5iscCs>|jj|}tg|D]}tj|^q||S(N(RtpoolsRR R(Rt search_keyt search_valueRt sim_poolstp((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR7lscCs;|jj}tg|D]}tj|^q||S(N(RtvolumesRR R(RR8R9Rtsim_volstv((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR<rscCs;|jj}tg|D]}tj|^q||S(N(RtdisksRR R(RR8R9Rt sim_diskstd((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR?xscCs.|jj|j||||}tj|S(N(Rt volume_createtidR R(Rtpoolt volume_namet size_bytest provisioningRtsim_vol((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRB~s cCs|jj|j|S(N(Rt volume_deleteRC(RtvolumeR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRIscCs(|jj|j||}tj|S(N(Rt volume_resizeRCR R(RRJtnew_size_bytesRRH((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRKs cCs@|dk r|j}n |j}|jj|||j||S(N(R RCtpool_idRtvolume_replicate(RRDtrep_typet volume_srctnameRt dst_pool_id((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRNs     cCs|jj|j|S(N(Rt!volume_replicate_range_block_sizeRC(RR.R((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRSs cCs"|jj||j|j||S(N(Rtvolume_replicate_rangeRC(RRORPt volume_desttrangesR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRTs cCs|jj|j|S(N(Rt volume_enableRC(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRWscCs|jj|j|S(N(Rtvolume_disableRC(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRXscCs;|jj}tg|D]}tj|^q||S(N(RtagsRR R(RR8R9Rtsim_agsta((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt access_groupsscCs.|jj||||j|}tj|S(N(Rtaccess_group_createRCR R(RRQtinit_idt init_typeR.Rtsim_ag((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR]s cCs|jj|j|S(N(Rtaccess_group_deleteRC(Rt access_groupR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRascCs+|jj|j|||}tj|S(N(Rtaccess_group_initiator_addRCR R(RRbR^R_RR`((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRcs cCs+|jj|j|||}tj|S(N(Rtaccess_group_initiator_deleteRCR R(RRbR^R_RR`((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRds cCs|jj|j|j|S(N(Rt volume_maskRC(RRbRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRes cCs|jj|j|j|S(N(Rt volume_unmaskRC(RRbRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRfs cCs8|jj|j|}g|D]}tj|^qS(N(Rt"volumes_accessible_by_access_groupRCR R(RRbRR=R>((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRgs cCs8|jj|j|}g|D]}tj|^qS(N(Rtaccess_groups_granted_to_volumeRCR R(RRJRR=R>((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRhs c CsX|r9|r9|dks$|dkr9ttjdn|jj||||||S(Ns?out_user and out_password only supported if inbound is supplied(R RRtINVALID_ARGUMENTRtiscsi_chap_auth(RR^tin_usert in_passwordtout_usert out_passwordR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRjs     cCs|jj|j|S(N(Rtvolume_child_dependencyRC(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRoscCs|jj|j|S(N(Rtvolume_child_dependency_rmRC(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRpscCs;|jj}tg|D]}tj|^q||S(N(RtfsRR R(RR8R9Rtsim_fsstf((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRqscCs(|jj|j||}tj|S(N(Rt fs_createRCR R(RRDRQRFRtsim_fs((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRtscCs|jj|j|S(N(Rt fs_deleteRC(RRqR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRvscCs(|jj|j||}tj|S(N(Rt fs_resizeRCR R(RRqRLRRu((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRws cCsG|dkr(|jj|j|d|S|jj|j||j|S(N(R Rtfs_cloneRC(Rtsrc_fst dest_fs_nametsnapshotR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRxs    cCsM|dkr+|jj|j||d|S|jj|j|||j|S(N(R Rt fs_file_cloneRC(RRqt src_file_nametdest_file_nameR{R((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR|s    cCs8|jj|j|}g|D]}tj|^qS(N(Rt fs_snapshotsRCR R(RRqRt sim_snapsR4((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRscCs|jj|j||S(N(Rtfs_snapshot_createRC(RRqt snapshot_nameR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRs cCs|jj|j|j|S(N(Rtfs_snapshot_deleteRC(RRqR{R((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR s cCs%|jj|j|j||||S(N(Rtfs_snapshot_restoreRC(RRqR{tfilest restore_filest all_filesR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRs cCs|jj|j||S(N(Rtfs_child_dependencyRC(RRqRR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRscCs|jj|j||S(N(Rtfs_child_dependency_rmRC(RRqRR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRscCsdgS(Ntstandard((RR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt export_authscCs>|jj|}tg|D]}tj|^q||S(N(RtexportsRR R(RR8R9Rtsim_expste((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRsc Cs=|jj||||||||| dd } tj| S(NRi(Rt fs_exportR R( Rtfs_idt export_patht root_listtrw_listtro_listtanon_uidtanon_gidt auth_typetoptionsRtsim_exp((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt export_fs#s cCs|jj|j|S(N(Rt fs_unexportRC(RtexportR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyt export_remove*scCs;|jj}tg|D]}tj|^q||S(N(Rt target_portsRR R(RR8R9Rtsim_tgtstt((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR-scCs|jj|S(N(Rtvolume_raid_info(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR3scCs|jj|S(N(Rtpool_member_info(RRDR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR6scCs|jj|S(N(Rtvolume_raid_create_cap_get(RR.R((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR9scCs|jj||||S(N(Rtvolume_raid_create(RRQt raid_typeR?t strip_sizeR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR<s cCs|jj|S(N(Rtvolume_ident_led_on(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRAscCs|jj|S(N(Rtvolume_ident_led_off(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRDscCs;|jj}tg|D]}tj|^q||S(N(Rt batteriesRR R(RR8R9Rt sim_batteriestb((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRGscCs|jj|S(N(Rtvolume_cache_info(RRJR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRNscCs|jj||S(N(Rt!volume_physical_disk_cache_update(RRJtpdcR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRQscCs|jj||S(N(Rtvolume_read_cache_policy_update(RRJtrcpR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRUscCs|jj||S(N(Rt volume_write_cache_policy_update(RRJtwcpR((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyRYsN(Gt__name__t __module__t__doc__RRRRRt staticmethodRRRR0R1R2R5R R7R<R?RBRIRKRNRSRTRWRXR\R]RaRcRdReRfRgRhRjRoRpRqRtRvRwRxR|RRRtFalseRRRRRRRRRRRRRRRt FLAG_RSVDRRRRR(((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyR s                                               N( tlsmRRRRRRRRRtlsm.plugin.sim.simarrayR R (((s</usr/lib/python2.7/site-packages/lsm/plugin/sim/simulator.pyts@plugin/sim/__init__.pyc000064400000000222147576505410011120 0ustar00 .P`c@sdS(N((((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/__init__.pytsplugin/sim/__init__.pyo000064400000000222147576505410011134 0ustar00 .P`c@sdS(N((((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/__init__.pytsplugin/sim/simarray.pyo000064400000263521147576505410011241 0ustar00 .P`c@sddlZddlZddlZddlZddlZddlmZddlmZmZm Z m Z m Z m Z m Z mZmZmZmZmZmZmZmZdZdZdZdefdYZd efd YZd efd YZdS( iN(tsize_human_2_size_bytes(tSystemtVolumetDisktPoolt FileSystemt AccessGroupt FsSnapshott NfsExporttmd5tLsmErrort TargetPortt ErrorNumbert JobStatustBatterytint_divcsfd}|S(Ncsiy||SWnQtjk r}t|dtkrct|ddrc|djjnt|dkrtt j dntt j dt|ntk rt|dtkrt|ddr|djjnnlt k rd}t|dtkrEt|ddrE|djjntt j dt|nXdS(Nitbs_objsdatabase is lockeds%Timeout to require lock on state files%Got unexpected error from sqlite3: %ssGot unexpected error: %s( tsqlite3tOperationalErrorttypetSimArraythasattrRttrans_rollbacktstrR R tTIMEOUTt PLUGIN_BUGt Exception(targstkargst sql_errort base_error(tmethod(s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytwrapper s,)  ))((RR ((Rs;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_handle_errorsscCsSdg}x:tddD])}|jtdtjddqWdj|S(s. Generate a random VPD83 NAA_Type3 ID t50iis%02xit(trangetappendRtrandomtrandinttjoin(tvpdt_((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _random_vpd:s 'cCs<i}x/t|jD]\}}||||dMscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6NscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6OscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6PscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6QscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6RscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6SscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6TscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6UscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6VscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6WscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6XscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6YscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6ZscCs|S(N((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6^scCs|S(N((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6_scCsdS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6`scCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6ascCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6bscCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6cscCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6dscCs t|dS(Ni(R(R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6escCst|ddS(Nii(R(R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6fscCst|ddS(Ni(R(R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6gscCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6hscCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6iscCst|ddS(Nii(R(R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6jscCst|ddS(Ni(R(R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6kscCs}|ttjjkr4ttjd|ntj||tkrlttjd||fntj||S(s Return a integer indicating how many disks should be used as real data(not mirrored or parity) disks. Treating RAID 5 and 6 using fixed parity disk. s0data_disk_count(): Got unsupported raid type(%d)s;data_disk_count(): Illegal disk count(%d) for raid type(%d)( tlistR4t_RAID_DISK_CHKtkeysR R RtFalset_RAID_PARITY_DISK_COUNT_FUNC(t raid_typet disk_count((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytdata_disk_countns (t__name__t __module__RtRAID_TYPE_JBODtRAID_TYPE_RAID0tRAID_TYPE_RAID1tRAID_TYPE_RAID3tRAID_TYPE_RAID4tRAID_TYPE_RAID5tRAID_TYPE_RAID6tRAID_TYPE_RAID10tRAID_TYPE_RAID15tRAID_TYPE_RAID16tRAID_TYPE_RAID50tRAID_TYPE_RAID60tRAID_TYPE_RAID51tRAID_TYPE_RAID61R8R;t staticmethodR>(((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR4Ks>                          t BackStorec BseZdZdeeefZdZdZdZdZdZ dZ dZ dd Z e jZejZejZejZd Zd Zd Zejejejejejejej gZ!d d dd dd dd dd dd dd d d gZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+e,dZ-dZ.dZ/e0e0dZ1dZ2d Z3d!Z4d"Z5d#Z6d$Z7d%Z8d&d&d'Z9d&d(Z:d)Z;e0d*Z<e0d+Z=d,Z>d-Z?d.Z@eAd/ZBd&d0ZCd1ZDd2ZEd3ZFd4ZGd5ZHd6ZId7ZJe0d8ZKd9ZLd:ZMeAd;ZNe0d<ZOd=ZPd>ZQd?ZRd@ZSdAZTdBZUdCZVdDZWeXdEZYdFZZdGZ[dHZ\dIZ]e0dJZ^dKZ_dLZ`dMZadNZbdOZcdPZddQZedRZfdSZgdTZhdUZidVZjdWZkdXZldYZmdZZnd[Zod\ZpRS(]s4.1sLSM_SIMULATOR_DATA_%s_%siiissim-01sLSM simulated storage plug-iniiii t#iiii i@icCstjj|sHtjtj|tjtjBtj|dn||_d|_ t j |dt t|ddd|_t|j_d}|d7}|d7}|d 7}|d 7}|d 7}|d 7}|d 7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d 7}|d!7}|d"7}|d#7}|jid$tjd%6tjd&6tjd'6tjd(6tjd)6}|jj}y|j|Wn_t jk rS}d*t|krJq|n/t jk r}ttj d+|jnXdS(,Nittimeoutitisolation_levelt IMMEDIATEsPRAGMA foreign_keys = ON; s CREATE TABLE systems ( id TEXT PRIMARY KEY, name TEXT NOT NULL, status INTEGER NOT NULL, status_info TEXT, read_cache_pct INTEGER, version TEXT NOT NULL); s% CREATE TABLE tgts ( id INTEGER PRIMARY KEY, port_type INTEGER NOT NULL, service_address TEXT NOT NULL, network_address TEXT NOT NULL, physical_address TEXT NOT NULL, physical_name TEXT NOT NULL); s CREATE TABLE pools ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, status INTEGER NOT NULL, status_info TEXT, element_type INTEGER NOT NULL, unsupported_actions INTEGER, raid_type INTEGER NOT NULL, parent_pool_id INTEGER, member_type INTEGER, strip_size INTEGER, total_space LONG); s CREATE TABLE disks ( id INTEGER PRIMARY KEY, total_space LONG NOT NULL, disk_type INTEGER NOT NULL, status INTEGER NOT NULL, disk_prefix TEXT NOT NULL, location TEXT NOT NULL, owner_pool_id INTEGER, role TEXT, vpd83 TEXT, rpm INTEGER, link_type INTEGER, FOREIGN KEY(owner_pool_id) REFERENCES pools(id) ON DELETE SET DEFAULT); s; CREATE TABLE volumes ( id INTEGER PRIMARY KEY, vpd83 TEXT NOT NULL, name TEXT UNIQUE NOT NULL, total_space LONG NOT NULL, consumed_size LONG NOT NULL, admin_state INTEGER, is_hw_raid_vol INTEGER, write_cache_policy INTEGER NOT NULL, read_cache_policy INTEGER NOT NULL, phy_disk_cache INTEGER NOT NULL, pool_id INTEGER NOT NULL, FOREIGN KEY(pool_id) REFERENCES pools(id) ON DELETE CASCADE); sx CREATE TABLE ags ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL); s CREATE TABLE inits ( id TEXT UNIQUE NOT NULL, init_type INTEGER NOT NULL, owner_ag_id INTEGER NOT NULL, FOREIGN KEY(owner_ag_id) REFERENCES ags(id) ON DELETE CASCADE); s  CREATE TABLE vol_masks ( vol_id INTEGER NOT NULL, ag_id INTEGER NOT NULL, FOREIGN KEY(vol_id) REFERENCES volumes(id) ON DELETE CASCADE, FOREIGN KEY(ag_id) REFERENCES ags(id) ON DELETE CASCADE); sV CREATE TABLE vol_reps ( rep_type INTEGER, src_vol_id INTEGER NOT NULL, dst_vol_id INTEGER NOT NULL, FOREIGN KEY(src_vol_id) REFERENCES volumes(id) ON DELETE CASCADE, FOREIGN KEY(dst_vol_id) REFERENCES volumes(id) ON DELETE CASCADE); s` CREATE TABLE fss ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, total_space LONG NOT NULL, consumed_size LONG NOT NULL, free_space LONG, pool_id INTEGER NOT NULL, FOREIGN KEY(pool_id) REFERENCES pools(id) ON DELETE CASCADE); s CREATE TABLE fs_snaps ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, fs_id INTEGER NOT NULL, timestamp LONG NOT NULL, FOREIGN KEY(fs_id) REFERENCES fss(id) ON DELETE CASCADE); s- CREATE TABLE fs_clones ( src_fs_id INTEGER NOT NULL, dst_fs_id INTEGER NOT NULL, FOREIGN KEY(src_fs_id) REFERENCES fss(id) ON DELETE CASCADE, FOREIGN KEY(dst_fs_id) REFERENCES fss(id) ON DELETE CASCADE); sd CREATE TABLE exps ( id INTEGER PRIMARY KEY, fs_id INTEGER NOT NULL, exp_path TEXT UNIQUE NOT NULL, auth_type TEXT, anon_uid INTEGER, anon_gid INTEGER, options TEXT, FOREIGN KEY(fs_id) REFERENCES fss(id) ON DELETE CASCADE); s CREATE TABLE exp_root_hosts ( host TEXT NOT NULL, exp_id INTEGER NOT NULL, FOREIGN KEY(exp_id) REFERENCES exps(id) ON DELETE CASCADE); s CREATE TABLE exp_rw_hosts ( host TEXT NOT NULL, exp_id INTEGER NOT NULL, FOREIGN KEY(exp_id) REFERENCES exps(id) ON DELETE CASCADE); s CREATE TABLE exp_ro_hosts ( host TEXT NOT NULL, exp_id INTEGER NOT NULL, FOREIGN KEY(exp_id) REFERENCES exps(id) ON DELETE CASCADE); s CREATE TABLE jobs ( id INTEGER PRIMARY KEY, duration REAL NOT NULL, timestamp TEXT NOT NULL, data_type INTEGER, data_id INTEGER); s CREATE TABLE batteries ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, type INTEGER NOT NULL, status INTEGER NOT NULL); s CREATE VIEW pools_view AS SELECT pool0.id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool0.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id, pool0.name, pool0.status, pool0.status_info, pool0.element_type, pool0.unsupported_actions, pool0.raid_type, pool0.member_type, pool0.parent_pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool0.parent_pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) parent_lsm_pool_id, pool0.strip_size, pool1.total_space total_space, pool1.total_space - pool2.vol_consumed_size - pool3.fs_consumed_size - pool4.sub_pool_consumed_size free_space, pool1.data_disk_count, pool5.disk_count FROM pools pool0 LEFT JOIN ( SELECT pool.id, ifnull(pool.total_space, ifnull(SUM(disk.total_space), 0)) total_space, COUNT(disk.id) data_disk_count FROM pools pool LEFT JOIN disks disk ON pool.id = disk.owner_pool_id AND disk.role = 'DATA' GROUP BY pool.id ) pool1 ON pool0.id = pool1.id LEFT JOIN ( SELECT pool.id, ifnull(SUM(volume.consumed_size), 0) vol_consumed_size FROM pools pool LEFT JOIN volumes volume ON volume.pool_id = pool.id GROUP BY pool.id ) pool2 ON pool0.id = pool2.id LEFT JOIN ( SELECT pool.id, ifnull(SUM(fs.consumed_size), 0) fs_consumed_size FROM pools pool LEFT JOIN fss fs ON fs.pool_id = pool.id GROUP BY pool.id ) pool3 ON pool0.id = pool3.id LEFT JOIN ( SELECT pool.id, ifnull(SUM(sub_pool.total_space), 0) sub_pool_consumed_size FROM pools pool LEFT JOIN pools sub_pool ON sub_pool.parent_pool_id = pool.id GROUP BY pool.id ) pool4 ON pool0.id = pool4.id LEFT JOIN ( SELECT pool.id, COUNT(disk.id) disk_count FROM pools pool LEFT JOIN disks disk ON pool.id = disk.owner_pool_id GROUP BY pool.id ) pool5 ON pool0.id = pool5.id GROUP BY pool0.id; s CREATE VIEW tgts_view AS SELECT id, 'TGT_PORT_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_tgt_id, port_type, service_address, network_address, physical_address, physical_name FROM tgts; s CREATE VIEW disks_view AS SELECT id, 'DISK_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_disk_id, disk_prefix || '_' || id name, total_space, disk_type, role, status, vpd83, rpm, link_type, location, owner_pool_id FROM disks; sf CREATE VIEW volumes_view AS SELECT id, 'VOL_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_vol_id, vpd83, name, total_space, consumed_size, admin_state, is_hw_raid_vol, write_cache_policy, read_cache_policy, phy_disk_cache, pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id FROM volumes; s CREATE VIEW fss_view AS SELECT id, 'FS_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_id, name, total_space, consumed_size, free_space, pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id FROM fss; s CREATE VIEW bats_view AS SELECT id, 'BAT_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_bat_id, name, type, status FROM batteries; sp CREATE VIEW fs_snaps_view AS SELECT id, 'FS_SNAP_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_snap_id, name, timestamp, fs_id, 'FS_ID_' || SUBSTR('{ID_PADDING}' || fs_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_id FROM fs_snaps; s; CREATE VIEW volumes_by_ag_view AS SELECT vol.id, 'VOL_ID_' || SUBSTR('{ID_PADDING}' || vol.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_vol_id, vol.vpd83, vol.name, vol.total_space, vol.consumed_size, vol.pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || vol.pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id, vol.admin_state, vol.is_hw_raid_vol, vol_mask.ag_id ag_id, vol.write_cache_policy, vol.read_cache_policy, vol.phy_disk_cache FROM volumes vol LEFT JOIN vol_masks vol_mask ON vol_mask.vol_id = vol.id; s CREATE VIEW ags_view AS SELECT ag.id, 'AG_ID_' || SUBSTR('{ID_PADDING}' || ag.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_ag_id, ag.name, CASE WHEN count(DISTINCT init.init_type) = 1 THEN init.init_type WHEN count(DISTINCT init.init_type) = 2 THEN {AG_INIT_TYPE_MIXED} ELSE {AG_INIT_TYPE_UNKNOWN} END init_type, group_concat(init.id, '{SPLITTER}') init_ids_str FROM ags ag LEFT JOIN inits init ON ag.id = init.owner_ag_id GROUP BY ag.id ORDER BY init.init_type; sO CREATE VIEW ags_by_vol_view AS SELECT ag_new.id, 'AG_ID_' || SUBSTR('{ID_PADDING}' || ag_new.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_ag_id, ag_new.name, ag_new.init_type, ag_new.init_ids_str, vol_mask.vol_id vol_id FROM ( SELECT ag.id, ag.name, CASE WHEN count(DISTINCT init.init_type) = 1 THEN init.init_type WHEN count(DISTINCT init.init_type) = 2 THEN {AG_INIT_TYPE_MIXED} ELSE {AG_INIT_TYPE_UNKNOWN} END init_type, group_concat(init.id, '{SPLITTER}') init_ids_str FROM ags ag LEFT JOIN inits init ON ag.id = init.owner_ag_id GROUP BY ag.id ORDER BY init.init_type ) ag_new LEFT JOIN vol_masks vol_mask ON vol_mask.ag_id = ag_new.id ; sg CREATE VIEW exps_view AS SELECT exp.id, 'EXP_ID_' || SUBSTR('{ID_PADDING}' || exp.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_exp_id, exp.fs_id, 'FS_ID_' || SUBSTR('{ID_PADDING}' || exp.fs_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_id, exp.exp_path, exp.auth_type, exp.anon_uid, exp.anon_gid, exp.options, exp2.exp_root_hosts_str, exp3.exp_rw_hosts_str, exp4.exp_ro_hosts_str FROM exps exp LEFT JOIN ( SELECT exp_t2.id, group_concat( exp_root_host.host, '{SPLITTER}') exp_root_hosts_str FROM exps exp_t2 LEFT JOIN exp_root_hosts exp_root_host ON exp_t2.id = exp_root_host.exp_id GROUP BY exp_t2.id ) exp2 ON exp.id = exp2.id LEFT JOIN ( SELECT exp_t3.id, group_concat( exp_rw_host.host, '{SPLITTER}') exp_rw_hosts_str FROM exps exp_t3 LEFT JOIN exp_rw_hosts exp_rw_host ON exp_t3.id = exp_rw_host.exp_id GROUP BY exp_t3.id ) exp3 ON exp.id = exp3.id LEFT JOIN ( SELECT exp_t4.id, group_concat( exp_ro_host.host, '{SPLITTER}') exp_ro_hosts_str FROM exps exp_t4 LEFT JOIN exp_ro_hosts exp_ro_host ON exp_t4.id = exp_ro_host.exp_id GROUP BY exp_t4.id ) exp4 ON exp.id = exp4.id GROUP BY exp.id; ; t0t ID_PADDINGt ID_FMT_LENtAG_INIT_TYPE_MIXEDtAG_INIT_TYPE_UNKNOWNtSPLITTERsalready existssLStored simulator state incompatible with simulator, please move or delete %s(!tostpathtexiststclosetopentO_WRONLYtO_CREATtchmodt statefiletNonet lastrowidRtconnecttintRtsql_connR3t row_factorytformatRPt _ID_FMT_LENRtINIT_TYPE_ISCSI_WWPN_MIXEDtINIT_TYPE_UNKNOWNt_LIST_SPLITTERR.t executescriptRRt DatabaseErrorR R tINVALID_ARGUMENT(tselfRcRRtsql_cmdtsql_curR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt__init__s#  '        ]'E     cCs{|j}t|dks)|d r-tSd|djkr^|ddtjkr^tSttj d|j dS(NitversionsLStored simulator state incompatible with simulator, please move or delete %s( tsim_sysstlenR:R9RPtVERSION_SIGNATUREtTrueR R RqRc(RrRw((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_check_version-s c Cs*|j|jr$|jdS|jditjd6tjd6tjd6dd6tj d6tj d 6t d }t d }g}xt d d D]n}|jdidd6|d6t jd6t jd6td6dd6t jd6d|d6|j|jqWg}xt d dD]}|jdidd6|d6t jd6t jd6td6dd6t jd6d|d6t|d kr#|j|jq#q#Wg}xt d dD]}|jdidd6|d6t jd6t jd6td6t jd6t jd6d|d6t|d kr|j|jqqWxrt d d D]a}|jdid!d6|d6t jd6t jd6td6t jd6t jd6d"|d6qZW|jdd#d$tjd%|d&tjtjBtjBtjBtj Bd'tj!tj"B}|j#dd(d)|d&tjtjBtjBd*||jdd+d$tjd%|d&tjtjBtjB|jdd,d&tjtjBtjBd$tj$d%||jd-it%j&d.6d/d06d/d16d/d26d3d46|jd-it%j'd.6d5d06d5d16d5d26d6d46|jd-it%j(d.6d7d06d8d16d9d26d:d46|jd-it%j(d.6d7d06d;d16d<d26d=d46|jd-it%j(d.6d7d06d>d16d<d26d=d46|jd?id@d6t)j*dA6t)jd6|jd?idBd6t)j+dA6t)jd6|jdSdS(Cs^ Raise error if version not match. If empty database found, initiate. NtsystemstidtnametstatusR#t status_infoRvtread_cache_pctt2TiBt512GiBiitdiskss2TiB SATA Diskt disk_prefixt total_spacet disk_typetvpd83i trpmt link_typesPort: %d Box: 1 Bay: 1tlocationis 2TiB SAS Diski:sPort: %d Box: 1 Bay: 2is512GiB SSD DisksPort: %d Box: 1 Bay: 3is 2TiB SSD DisksPort: %d Box: 1 Bay: 4sPool 1R<t sim_disk_idst element_typetunsupported_actionssPool 2(sub pool of Pool 1)tparent_pool_idtsizesPool 3t lsm_test_aggrttgtst port_types50:0a:09:86:99:4b:8d:c5tservice_addresstnetwork_addresstphysical_addresstFC_a_0bt physical_names50:0a:09:86:99:4b:8d:c6t FCoE_b_0cs"iqn.1986-05.com.example:sim-tgt-03s sim-iscsi-tgt-3.example.com:3260sa4:4e:31:47:f4:e0t iSCSI_c_0ds 10.0.0.1:3260sa4:4e:31:47:f4:e1t iSCSI_c_0es%[2001:470:1f09:efe:a64e:31ff::1]:3260t batteriess'Battery SIMB01, 8000 mAh, 05 March 2016Rs&Capacitor SIMC01, 500 J, 05 March 2016(,t trans_beginR{t trans_committ _data_addRPtSYS_IDtSYS_NAMERt STATUS_OKRyt_DEFAULT_READ_CACHE_PCTRR$Rt TYPE_SATAR+t LINK_TYPE_ATAR%RetTYPE_SASt LINK_TYPE_SASRxtTYPE_SSDtRPM_NON_ROTATING_MEDIUMtsim_pool_create_from_diskRRCRtELEMENT_TYPE_POOLtELEMENT_TYPE_FStELEMENT_TYPE_VOLUMEtELEMENT_TYPE_DELTAtELEMENT_TYPE_SYS_RESERVEDtUNSUPPORTED_VOLUME_GROWtUNSUPPORTED_VOLUME_SHRINKtsim_pool_create_sub_poolRBR tTYPE_FCt TYPE_FCOEt TYPE_ISCSIRt TYPE_CHEMICALtTYPE_CAPACITOR(Rrt size_bytes_2ttsize_bytes_512gt pool_1_diskstittest_pool_diskstssd_pool_diskst pool_1_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytcheck_version_and_init;s.                                                       cCs2|jj}|j||j|_|jS(s9 Execute sql command and get all output. (RhR.texecuteRetfetchall(RrRsRt((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _sql_execs  cCsd|}|j|S(NsSELECT * FROM %s(R(Rrt table_nameRs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _get_tables cCs|jjddS(NsBEGIN IMMEDIATE TRANSACTION;(RhR(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR scCs|jjdS(N(Rhtcommit(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRscCs|jjdS(N(Rhtrollback(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRscCst|j}gt|jD]$}|dkr=dn t|^q%}d|ddj|ddj|f}|j|dS(NR#s INSERT INTO %s (%s) VALUES (%s);s'%s's', '(R7R9tvaluesRdRR(R(RrRt data_dictR9tvRRs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs=cCsyd||f}|j|}|rqt|dkr;dSt|dkrU|dSttjdtn|SdS(NsSELECT * FROM %s WHERE %siis%_data_find(): Got non-unique data: %s(RRxRdR R Rtlocals(Rrttablet conditiont flag_uniqueRst sim_datas((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _data_findscCsI|dkr"d|||f}nd||||f}|j|dS(Ns#UPDATE %s SET %s=NULL WHERE id='%s's#UPDATE %s SET %s='%s' WHERE id='%s'(RdR(RrRtdata_idt column_nametvalueRs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _data_update-s  cCs!d||f}|j|dS(NsDELETE FROM %s WHERE %s;(R(RrRRRs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _data_delete7scCsH|jditjdtjd6tjd6|d6|d6|jS(s* Return a job id(Integer) tjobst LSM_SIM_TIMEtdurationt timestampt data_typeR(RR[tgetenvRPtJOB_DEFAULT_DURATIONttimeRe(Rrt job_data_typeR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_job_create;s  cCs|jdd|dS(NRsid="%s"(R(Rrt sim_job_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_job_deleteJscCsE|jdd|dt}|d kr=ttjdnttjt|d|dd}d }d }|dkrd}n|dkr8d}|d t j kr|j |d }|d }q8|d t j kr|j |d }|d }q8|d t jkr8|j|d }|d }q8n|||fS( sg Return (progress, data_type, data) tuple. progress is the integer of percent. Rsid=%sRs Job not foundRRidiRRN(RRzRdR R t NOT_FOUND_JOBRgRtfloatRPtJOB_DATA_TYPE_VOLt sim_vol_of_idtJOB_DATA_TYPE_FSt sim_fs_of_idtJOB_DATA_TYPE_FS_SNAPtsim_fs_snap_of_id(RrRtsim_jobtprogresstdataR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_job_statusMs.  )     cCs |jdS(s0 Return a list of sim_sys dict. R|(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRwpscCs$td|jdd|DS(Ncss|]}|dVqdS(t lsm_disk_idN((t.0R0((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys xst disks_viewsowner_pool_id="%s"(R7R(Rrt sim_pool_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytlsm_disk_ids_of_poolvscCs |jdS(s1 Return a list of sim_disk dict. R(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_disks|scCs |jdS(s1 Return a list of sim_pool dict. t pools_view(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_poolsscCs|jd|tjdS(NRR(t_sim_data_of_idR tNOT_FOUND_POOL(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_pool_of_idsic Cs7|dkrtj}n|tjks6|tjkrBtj}n|jdi|d6tjd6dd6|d6|d6|d 6tj d 6|d 6t j |t |}|j }x>|| D]2} |jd | d ||jd | ddqWx>||D]2} |jd | d ||jd | ddqW|S(NitpoolsR~RR#RRRR<t member_typet strip_sizeRt owner_pool_idtroletDATAtPARITY(RPtDEFAULT_STRIP_SIZERRCRAtBLK_SIZERRRtMEMBER_TYPE_DISKR4R>RxReR( RrR~RR<RRRR>Rt sim_disk_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs<       cCs_|jdi |d6tjd6dd6|d6|d6tjd6tjd 6|d 6|d 6|jS( NRR~RR#RRRR<RRR(RRRRtRAID_TYPE_OTHERtMEMBER_TYPE_POOLRe(RrR~RRRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs    cCs|jd|ddS(Ns3SELECT COUNT(id) FROM disks WHERE owner_pool_id=%s;i(R(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_pool_disks_countscCs|jd|ddS(NsCSELECT COUNT(id) FROM disks WHERE owner_pool_id=%s and role='DATA';i(R(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_pool_data_disks_countscCs+|r|jdd|S|jdSdS(s0 Return a list of sim_vol dict. tvolumes_by_ag_viewsag_id=%st volumes_viewN(RR(Rrt sim_ag_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_volsscCsO|j|d|dt}|dkrK|rDt|d|qKdSn|S(Nsid=%sRs %s not found(RRzRdR (RrRRt lsm_error_not data_nametsim_data((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs cCs|jd|tjdS(sD Return sim_vol if found. Raise error if not found. RR(RR tNOT_FOUND_VOLUME(Rrt sim_vol_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs cCs8|j|}|d|kr4ttjdndS(Nt free_spacesInsufficient space in pool(RR R tNOT_ENOUGH_SPACE(RrRt size_bytestsim_pool((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_check_pool_free_spaces cCs|tjdtjtjS(Ni(RPR(R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_block_roundingscCstj|}|j||t}t|d<||d<||d<||d<||dQsR.s ag_id="%s"(R7R(RrR ((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_vol_ids_of_masked_agOs cCs$td|jdd|DS(Ncss|]}|dVqdS(R/N((RR6((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys VsR.s vol_id="%s"(R7R(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR'Ts cCstj|}|j|}|d|krCttjdn|j|d}||d}|dkr|dtj@rttj dn|d|krttj dqn&|dtj @rttj dn|j d |d||j d |d |dS( NRs%Volume size is identical to requestedRiRs.Requested pool does not allow volume size growRsInsufficient space in poolRR( RPRRR R R2RRRt NO_SUPPORTRRR(RrRtnew_size_bytesR%Rt increment((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_resizeYs0    cCs1|j|td|jdd|DS(sL Return a list of dst_vol_id for provided source volume ID. css|]}|dVqdS(t dst_vol_idN((RR0((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys stvol_repsssrc_vol_id="%s"(RR7R(Rrtsrc_sim_vol_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR)|s  cCs|j||j|||kr*dS|tjkr=dStd|jdd|D}t|dkrydS|jdi|d6|d6|d6dS(Ncss|]}|dVqdS(t src_vol_idN((Rtr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys sR=sdst_vol_id="%s"iR?R<trep_type(RRtREPLICATE_COPYR7RRxR(RrR>R,RAt blk_rangestcur_src_sim_vol_ids((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_replicas"    cCs<|j|s$ttjdn|jdd|dS(Ns+Provided volume is not a replication sourceR=ssrc_vol_id="%s"(R)R R R2R(RrR>((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_src_replica_breaks  cCsN|j|}|d|kr4ttjdn|jd|d|dS(NRs,Volume admin state is identical to requestedR(RR R R2R(RrRtnew_admin_stateR%((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_state_changes cCs%|djtj|d<|d=|S(s= Update 'init_type' and 'init_ids' of sim_ag t init_ids_strtinit_ids(tsplitRPRn(tsim_ag((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_ag_formats cCsN|r|jdd|}n|jd}g|D]}tj|^q5S(Ntags_by_vol_views vol_id=%stags_view(RRRPRM(RrRtsim_agsta((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRPs cCs\y)|jdi|d6|d6|d6Wn,tjk rW}ttjd|nXdS(NtinitsR}t init_typet owner_ag_ids6Initiator '%s' is already in use by other access group(RRR#R R tEXISTS_INITIATOR(RrRStinit_idR R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_init_createscCsdS(N(Rd(RrRVtin_usertin_passtout_usertout_pass((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytiscsi_chap_auth_setscCsjy$|jdi|d6|j}Wn,tjk rR}ttjd|nX|j||||S(NtagsR~s1Name '%s' is already in use by other access group(RReRR#R R R$RW(RrR~RSRVR R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_ag_creates cCsI|j||j|r1ttjdn|jdd|dS(Ns!Access group has volume masked toR]sid="%s"(R1R7R R R(R(RrR ((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_ag_deletes   cCs~|j|}||dkr4ttjdn|tjkrg|tjkrgttjdn|j|||dS(NRJs!Initiator already in access groups.Only support iSCSI IQN and WWPN initiator type( R1R R R2RtINIT_TYPE_ISCSI_IQNtINIT_TYPE_WWPNR8RWRd(RrR RVRSRL((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_ag_init_adds  cCsw|j|}||dkr4ttjdnt|ddkr_ttjdn|jdd|dS(NRJs(Initiator is not in defined access groupis6Refused to remove the last initiator from access groupRRsid="%s"(R1R R R2RxtLAST_INIT_IN_ACCESS_GROUPR(RrR RVRL((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_ag_init_deletes  cCs,|jd|tjd}tj||S(NROs Access Group(RR tNOT_FOUND_ACCESS_GROUPRPRM(RrR RL((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR1s    cCs |jdS(s/ Return a list of sim_fs dict. tfss_view(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fssscCs.tj}|sd}n|jd||dS(NRfs File System(R t NOT_FOUND_FSRdR(Rrt sim_fs_idt raise_errorR ((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR"s   cCstj|}|j||y7|jdi|d6|d6|d6|d6|d6Wn,tjk r}ttjd|nX|j S(NtfssR~RRRRs'Name '%s' is already in use by other fs( RPRRRRR#R R R$Re(RrR~RRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_fs_create*s cCsI|j||j|r1ttjdn|jdd|dS(Ns*Requested file system has child dependencyRksid="%s"(Rtclone_dst_sim_fs_ids_of_srcR R R*R(RrRi((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_fs_delete=s   cCstj|}|j|}|d|krCttjdn|j|d}||dkr|d||dkrttjdn|jd|d||jd|d||jd|d|dS(NRs*File System size is identical to requestedRRsInsufficient space in poolRkR( RPRRR R R2RRR(RrRiR9tsim_fsR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_fs_resizeFs" cCs!|j||jdd|S(Nt fs_snaps_views fs_id="%s"(RR(RrRi((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_fs_snaps`s cCsJ|jd|tjd}|rF|d|krFttjdn|S(NRqsFile system snapshottfs_idsFDefined file system snapshot ID is not belong to requested file system(RR tNOT_FOUND_FS_SSR (Rrtsim_fs_snap_idRit sim_fs_snap((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRds   cCst|j|y5|jdi|d6|d6ttjd6Wn(tjk rl}ttjdnX|j S(Ntfs_snapsR~RsRs6The name is already used by other file system snapshot( RRRgRRR#R R R$Re(RrRiR~R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_snap_createos  cCs*|j||r&|j||ndS(N(RR(RrRiRutfilest restore_filestflag_all_files((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_snap_restores cCs5|j||j|||jdd|dS(NRwsid="%s"(RRR(RrRuRi((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_snap_deletes cCsd|}|j|dS(Ns&DELETE FROM fs_snaps WHERE fs_id='%s';(R(RrRiRs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_snap_del_by_fss cCsU|j||j||r3|j||n|jdi|d6|d6dS(Nt fs_clonest src_fs_idt dst_fs_id(RRR(Rrt src_sim_fs_idt dst_sim_fs_idRu((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_fs_clones  cCs*|j||r&|j||ndS(N(RR(RrRit src_fs_namet dst_fs_nameRu((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_file_clones cCs1|j|td|jdd|DS(sM Return a list of dst_fs_id for provided clone source fs ID. css|]}|dVqdS(RN((RR0((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys sRssrc_fs_id="%s"(RR7R(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRms  cCs|jdd|dS(NRssrc_fs_id="%s"(R(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_src_clone_breakscCs`xYdddgD]H}d|}||rG||jtj||st exps_view(R7R(Rr((Rrs;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_expsscCs"|j|jd|tjdS(NRs NFS Export(RRR tNOT_FOUND_NFS_EXPORT(Rrt sim_exp_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_exp_of_ids c Cs0|dkr dtd }n|j|y>|jdi|d6|d6|d6|d6|d6| d 6Wn(tjk r} ttjd nX|j } x,|D]$} |jd i| d 6| d 6qWx,|D]$} |jdi| d 6| d 6qWx,|D]$}|jdi|d 6| d 6qW| S(Ns /nfs_exp_%sitexpsRstexp_pathtanon_uidtanon_gidt auth_typetoptionss/Export path is already used by other NFS exporttexp_root_hoststhosttexp_idt exp_rw_hostst exp_ro_hosts( RdR+RRRR#R R R$Re(RrRiRRRRRRRRRRt root_hosttrw_hosttro_host((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_exp_createsJ       cCs%|j||jdd|dS(NRsid="%s"(RR(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_exp_deletes cCs |jdS(s0 Return a list of sim_tgt dict. t tgts_view(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_tgtsscCs |jdS(s0 Return a list of sim_bat dict. t bats_view(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_batsscCs'|j||jd|d|dS(NRR(RR(RrRtpdc((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_pdc_sets cCs'|j||jd|d|dS(NRR(RR(RrRtrcp((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_rcp_sets cCs'|j||jd|d|dS(NRR(RR(RrRtwcp((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_wcp_sets (qR?R@tVERSIONR RyRRRRRRRRRtMODE_HARDWARE_RAIDtSYS_MODERtWRITE_CACHE_POLICY_AUTOR tREAD_CACHE_POLICY_ENABLEDR!tPHYSICAL_DISK_CACHE_DISABLEDR"RRnRkRBRCRFRGRHRKRLtSUPPORTED_VCR_RAID_TYPEStSUPPORTED_VCR_STRIP_SIZESRuR{RRRRRRRR:RRRRdRRRRwRRRRRRRRR RRRRORR&R-R4R5R7R'R;R)RERFRHRMRPRWR\R^R_RbRdR1RgRzRRlRnRpRrRRxR|R}R~RRRmRRRRRRRRRRR(((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRPs         *         #      )           #                   2     RcBs%eZejdejdZedZedZ edZ edZ edZ edZ edZed Zed ZdOdOd Zed d Zed dZed dZed dZedZedZed dZedZedZedZed dZedZedZ ed e!d dZ"ed dZ#ed dZ$ed dZ%ed dZ&ed dZ'ed d Z(ed d!Z)ed d"Z*ed d#Z+ed$Z,ed%Z-ed e!d&Z.ed d'Z/ed d(Z0ed d)Z1ed d*Z2ed+Z3ed d,Z4ed d-Z5ed d.Z6ed/Z7ed e!d0Z8ed d1Z9ed2Z:ed d3Z;ed d4Z<ed d5Z=ed6Z>ed7Z?ed d8Z@ed d9ZAed d:ZBed d;ZCed d<ZDed d=ZEed d>ZFed d?ZGed d@ZHedAZIedBZJedCZKedDZLedEZMedFZNed dGZOed dHZPedIZQedJZRedKZSed dLZTed dMZUed dNZVRS(Pt LSM_SIM_DATAs /lsm_sim_datacCs4yt|tj SWntk r/|nXdS(N(RgRPRkt ValueError(tlsm_idt lsm_error((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_lsm_id_to_sim_ids cCstj|ttjdS(Ns Job not found(RRR R R(tjob_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_job_id_of&scCstj|ttjdS(NsPool not found(RRR R R(R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_pool_id_of+scCstj|ttjdS(NsVolume not found(RRR R R(R0((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_vol_id_of0scCstj|ttjdS(NsFile system not found(RRR R Rh(Rs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _sim_fs_id_of6scCstj|ttjdS(NsFile system snapshot not found(RRR R Rt(tsnap_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_fs_snap_id_of<scCstj|ttjdS(NsFile system export not found(RRR R R(R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_exp_id_ofCscCstj|ttjdS(NsFile system export not found(RRR R R(R/((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _sim_ag_id_ofJscCsM|dkrtj}nt|||_|jj||_||_dS(N(RdRt SIM_DATA_FILERPRRRcRR(RrRcRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRuQs     cCs&|jj||}dtj|fS(Ns JOB_ID_%0*d(RRRPRk(RrRt sim_data_idR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _job_create[s  ic Cstj|}|jj|\}}}tj}|dkrKtj}nd}|tj krrtj |}nB|tj krtj |}n!|tj krtj|}n|||fS(Nid(RRRRR t INPROGRESStCOMPLETERdRPRt_sim_vol_2_lsmRt _sim_fs_2_lsmRt_sim_fs_snap_2_lsm( RrRtflagsRRRR RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt job_status`s    cCs7|jj|jjtj||jjdS(N(RRRRRRRd(RrRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytjob_freets  cCs1t|jtt|d|_||_dS(Ni(RPRcRgRRRRRd(RrtmsR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt time_out_set{s$ cCs|jS(N(RR(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt time_out_getsc Cs@t|d|d|d|dd|ddtjd|d S( NR}R~RRt _fw_versionRvt_modet_read_cache_pctR(RRPR(tsim_sys((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_sys_2_lsms  cCstd|jjDS(Ncss|]}tj|VqdS(N(RR(RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(R7RRw(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR|scCsa|jtjkr'ttjdn|jj|jjdtjd||jj dS(NsSystem not foundR|R( R}RPRR R tNOT_FOUND_SYSTEMRRRRRd(Rrtsystemtread_pctR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsystem_read_cache_pct_updates    c CsOt|d|d|dtjtt|dtj|dtj|dS(Nt lsm_vol_idR~RRRt lsm_pool_id(RRPRRgRR(R%((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs  cCstd|jjDS(Ncss|]}tj|VqdS(N(RR(RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(R7RR (Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRsc Cs{|d}|d}|d}|d}|d}|d}tj}|d}|d} t|||| ||||| S( NRR~RRRRRR(RPRR( RRR~RRRRtsys_idRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_pool_2_lsms         cCs=|jj|jj}|jjtd|DS(Ncss|]}tj|VqdS(N(RR(RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(RRRRR7(RrRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs   cCstj}|ddkr)|tjO}nt|d|d|dtjtt|dtj|tjd|dd|d d |d d |d S(NRRR~RRt_vpd83Rt _locationRt_rpmRt _link_typeR( RRRdt STATUS_FREERPRRgRR(tsim_diskt disk_status((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_disk_2_lsms   cCstd|jjDS(Ncss|]}tj|VqdS(N(RR(RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(R7RR(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRsc Csy|tkr|jjn|jj||tj|d|}|rM|S|jtj|} |jj | dfS(s The '_internal_use' parameter is only for SimArray internal use. This method will return the new sim_vol id instead of job_id when '_internal_use' marked as True. RN( R:RRR&RRRRPRRRd( RrRtvol_nameRtthinpRt _internal_uset_is_hw_raid_voltnew_sim_vol_idR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_creates    cCsC|jj|jjtj||j}|jj|S(N(RRR-RRRR(RrR0RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_deletes    cCs[|jjtj|}|jj|||jtj|}|jj|dfS(N( RRRRR;RRPRRRd(RrR0R9RRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_resizes  c Cs|jjtj|}|jj|}|j|||dtjdt}|jj ||||j t j |} |jj | dfS(NRR(RRRRRRRtPROVISION_FULLRzRERRPRRRd( Rrt dst_pool_idRAR?t new_vol_nameRR>t src_sim_volR,R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_replicates   cCs+|tjkr$ttjdntjS(NsSystem not found(RPRR R RR(RrRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt!volume_replicate_range_block_sizes  cCsU|jj|jjtj|tj||||j}|jj|S(N(RRRERRRR(RrRAR?R<trangesRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_replicate_range#s     cCs=|jj|jjtj|tj|jjdS(N( RRRHRRRRRRd(RrR0R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_enable5s    cCs=|jj|jjtj|tj|jjdS(N( RRRHRRRtADMIN_STATE_DISABLEDRRd(RrR0R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_disable=s    cCsFtj|}|jj|}x|D]}||kr(tSq(WtS(N(RRRR)RzR:(RrR0RR>R+R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_child_dependencyEs   cCsC|jj|jjtj||j}|jj|S(N(RRRFRRRR(RrR0RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_child_dependency_rm`s     cCs0t|d|d|d|d|dtjS(Nt lsm_fs_idR~RRR(RRPR(Ro((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRkscCstd|jjDS(Ncss|]}tj|VqdS(N(RR(Rtf((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys ss(R7RRg(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfsqscCsm|s|jjn|jj||tj|}|rA|S|jtj|}|jj|dfS(N( RRRlRRRRPRRRd(RrRtfs_nameRRRt new_sim_fs_idR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_createus  cCsC|jj|jjtj||j}|jj|S(N(RRRnRRRR(RrRsRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_deletes    cCs[tj|}|jj|jj|||jtj|}|jj|dfS(N( RRRRRpRRPRRRd(RrRsR9RRiR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_resizes   c Cs|jjd}|r+tj|}ntj|}|jj|}|d}|j|||ddt} |jj || ||j t j | } |jj | dfS(NRRR(RRRdRRRRRRzRRRPRR( RrRRRRRuRt src_sim_fsRRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_clones    cCsj|jjd}|r+tj|}n|jjtj|||||j}|jj|S(N( RRRdRRRRRR(RrRsRRRRRuR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_file_clones    cCst|d|d|dS(Ntlsm_fs_snap_idR~R(R(Rv((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs cCs)td|jjtj|DS(Ncss|]}tj|VqdS(N(RR(Rts((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(R7RRrRR(RrRsR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_snapshotss cCsW|jj|jjtj||}|jtj|}|jj|dfS(N( RRRxRRRRPRRRd(RrRst snap_nameRRuR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_snapshot_creates   cCsO|jj|jjtj|tj||j}|jj|S(N(RRR}RRRRR(RrRsRRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_snapshot_deletes     c Csm|jjd}|r+tj|}n|jjtj||||||j}|jj|S(N( RRRdRRR|RRR( RrRsRRyRzR{RRuR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_snapshot_restores     cCstj|}|tkr+|jjn|jj|gkr{|jj|gkr{|tkrw|jjntS|tkr|jjntS(N( RRR:RRRmRrRRz(RrRsRyRRRi((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_child_dependencys   cCs|jj|j||dttkr@ttjdntj |}|jj ||jj ||j }|jj |S(s Assuming API defination is break all clone relationship and remove all snapshot of this source file system. Rs9No snapshot or fs clone target found for this file system(RRRRzR:R R R2RRRR~RR(RrRsRyRRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_child_dependency_rms    c CsMt|d|d|d|d|d|d|d|d|d |d  S( Nt lsm_exp_idRRRRRRRRR(R(R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_exp_2_lsm s cCs)g|jjD]}tj|^qS(N(RRRR(RrRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytexports sc Csl|jj|jjtj||||||||| } |jj| } |jjtj| S(N(RRRRRRRR( RrRsRRRRRRRRRRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_export s   cCs7|jj|jjtj||jjdS(N(RRRRRRRd(RrRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_unexport( s  cCs)t|d|d|d|dtjS(Nt lsm_ag_idR~RJRS(RRPR(RL((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _sim_ag_2_lsm/ scCstd|jjDS(Ncss|]}tj|VqdS(N(RR(RRQ((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys 7 s(R7RRP(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR]5 scCsu|tjkr$ttjdn|jj|jj|||}|jj|}|jj t j |S(NsSystem not found( RPRR R RRRR^R1RRR(RrR~RVRSRRt new_sim_ag_idt new_sim_ag((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytaccess_group_create9 s   cCs7|jj|jjtj||jjdS(N(RRR_RRRRd(RrR/R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytaccess_group_deleteE s  cCs^tj|}|jj|jj||||jj|}|jjtj|S(N(RRRRRbR1RR(RrR/RVRSRR R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytaccess_group_initiator_addL s   cCs[tj|}|jj|jj|||jj|}|jjtj|S(N(RRRRRdR1RR(RrR/RVRSRR RL((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytaccess_group_initiator_deleteU s   cCsC|jj|jjtj|tj||jjdS(N(RRR4RRRRRd(RrR/R0R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_mask_ s     cCsC|jj|jjtj|tj||jjdS(N(RRR5RRRRRd(RrR/R0R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_unmaskh s     cCsX|jj|jjdtj|}|jjg|D]}tj|^q?S(NR (RRR RRRR(RrR/RR R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt"volumes_accessible_by_access_groupq s    cCsX|jj|jjdtj|}|jjg|D]}tj|^q?S(NR(RRRPRRRR(RrR0RRPRQ((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytaccess_groups_granted_to_volume{ s    cCs:|jj|jj||||||jjdS(N(RRR\RRd(RrRVRXRYRZR[R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytiscsi_chap_auth s    cCs7t|d|d|d|d|d|dtjS(Nt lsm_tgt_idRRRRR(R RPR(tsim_tgt((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_tgt_2_lsm s cCstd|jjDS(Ncss|]}tj|VqdS(N(RR%(Rtt((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(R7RR(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt target_ports scCs=|jjtj|jttjd}tj }t j }|dt j krk|jj|d}n|d}|d}|d}|}|t jks|t jkr|||||gS|t jkrttjd|dn|t jks |t jkrtj }nt|d |}|||||gS( NsPool not foundRRR<R=Rs;volume_raid_info(): Got unsupported RAID_TYPE_MIXED pool %sRR>(RRRRRR R RRPRRtOPT_IO_SIZE_UNKNOWNRRtRAID_TYPE_UNKNOWNRtRAID_TYPE_MIXEDRRCRARg(Rrtlsm_volRt min_io_sizet opt_io_sizeR<R=R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_raid_info s4        cCs|jjtj|jttjd}|d}g}|tj kr\|dg}n1|tj kr|jj |d}n tj }|d||fS(NsPool not foundRtparent_lsm_pool_idR}R<( RRRRR}R R RRRRRtMEMBER_TYPE_UNKNOWN(Rrtlsm_poolRRt member_ids((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytpool_member_info s   cCs7|jtjkr'ttjdntjtjfS(NsSystem not found(R}RPRR R RRR(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_raid_create_cap_get s  c Cs|tjkr$ttjdn|tjkr?tj}n$|tjkrcttjdn|j j d|}g|D]'}t j |j ttjd^q}x:|D]2}|jtj@sttjd|j qqWyD|j jd|d|d|d tjd tjtjBd |} Wn,tjk r]} ttjd |nX|j j| } |j| d || ddtjdtdd} |j j| } |j j t j!| S(Ns%Provided 'raid_type' is not supporteds&Provided 'strip_size' is not supportedsPool for volume %ssDisk not founds'Disk %s is not in DISK.STATUS_FREE modeR~R<RRRRs+Name '%s' is already in use by other volumeRRiRRi("RPRR R R8RtVCR_STRIP_SIZE_DEFAULTRRRRRRR}tNOT_FOUND_DISKRRRt DISK_NOT_FREERRRRRRR#R$RRRRzRRR(RrR~R<RRt pool_nameR0RtdiskRRRRR%((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_raid_create sP     1       cCs7tj|jttjd}|jj|}dS(NsVolume not found( RRR}R R RRRRd(RrtvolumeRt sim_volume_idR%((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_ident_led_on s   cCs7tj|jttjd}|jj|}dS(NsVolume not found( RRR}R R RRRRd(RrR;RR<R%((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_ident_led_off s   cCs)t|d|d|d|dtjS(Nt lsm_bat_idR~RR(RRPR(tsim_bat((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_bat_2_lsm! scCstd|jjDS(Ncss|]}tj|VqdS(N(RRA(RR&((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys ( s(R7RR(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR& scCs>|jjtj|jttjd}tj }tj }t }x3|jj D]"}|dt jkrUt}qUqUW|dtjkr|rtj}qn>|dtjkrtj}n|dtjkrtj}n|dtjkrtj}n|dtjkrtj}n|d||d||dgS(NsVolume not foundRRRR(RRRRR}R R RRt WRITE_CACHE_STATUS_WRITE_THROUGHtREAD_CACHE_STATUS_DISABLEDR:RRRRzRtWRITE_CACHE_STATUS_WRITE_BACKtWRITE_CACHE_POLICY_WRITE_BACKtWRITE_CACHE_POLICY_UNKNOWNtWRITE_CACHE_STATUS_UNKNOWNRtREAD_CACHE_STATUS_ENABLEDtREAD_CACHE_POLICY_UNKNOWNtREAD_CACHE_STATUS_UNKNOWN(RrR+R%twrite_cache_statustread_cache_statustflag_battery_okR@((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_cache_info* s2           cCsR|jjtj|jttjd}|jj|||jj dS(NsVolume not found( RRRRR}R R RRR(RrR;RRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt!volume_physical_disk_cache_updateL s   cCsR|jjtj|jttjd}|jj|||jj dS(NsVolume not found( RRRRR}R R RRR(RrR;RRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_write_cache_policy_updateU s   cCsR|jjtj|jttjd}|jj|||jj dS(NsVolume not found( RRRRR}R R RRR(RrR;RRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_read_cache_policy_update^ s   N(WR?R@R[Rttempfilet gettempdirRRORRRRRRRRR!RuRdRRRRRRR|RRRRRRRR:RRRRRRRRRRRRRRRRRRR R R RRRRRRRRR]RRRRRRR R!R"R%R'R.R3R4R:R=R>RARRNRORPRQ(((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs           & 4  "(R&RRR[RRtlsmRRRRRRRRRR R R R R RRR!R+R3tobjectR4RPR(((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyts$     d  8plugin/sim/simarray.py000064400000275600147576505410011063 0ustar00# Copyright (C) 2011-2016 Red Hat, Inc. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, see . # # Author: tasleson # Gris Ge import random import tempfile import os import time import sqlite3 from lsm import (size_human_2_size_bytes) from lsm import (System, Volume, Disk, Pool, FileSystem, AccessGroup, FsSnapshot, NfsExport, md5, LsmError, TargetPort, ErrorNumber, JobStatus, Battery, int_div) def _handle_errors(method): def wrapper(*args, **kargs): try: return method(*args, **kargs) except sqlite3.OperationalError as sql_error: if type(args[0]) is SimArray and hasattr(args[0], 'bs_obj'): args[0].bs_obj.trans_rollback() if str(sql_error) == 'database is locked': raise LsmError( ErrorNumber.TIMEOUT, "Timeout to require lock on state file") raise LsmError( ErrorNumber.PLUGIN_BUG, "Got unexpected error from sqlite3: %s" % str(sql_error)) except LsmError: if type(args[0]) is SimArray and hasattr(args[0], 'bs_obj'): args[0].bs_obj.trans_rollback() raise except Exception as base_error: if type(args[0]) is SimArray and hasattr(args[0], 'bs_obj'): args[0].bs_obj.trans_rollback() raise LsmError( ErrorNumber.PLUGIN_BUG, "Got unexpected error: %s" % str(base_error)) return wrapper def _random_vpd(): """ Generate a random VPD83 NAA_Type3 ID """ vpd = ['50'] for _ in range(0, 7): vpd.append(str('%02x' % (random.randint(0, 255)))) return "".join(vpd) def _dict_factory(cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d class PoolRAID(object): _RAID_DISK_CHK = { Volume.RAID_TYPE_JBOD: lambda x: x > 0, Volume.RAID_TYPE_RAID0: lambda x: x > 0, Volume.RAID_TYPE_RAID1: lambda x: x == 2, Volume.RAID_TYPE_RAID3: lambda x: x >= 3, Volume.RAID_TYPE_RAID4: lambda x: x >= 3, Volume.RAID_TYPE_RAID5: lambda x: x >= 3, Volume.RAID_TYPE_RAID6: lambda x: x >= 4, Volume.RAID_TYPE_RAID10: lambda x: x >= 4 and x % 2 == 0, Volume.RAID_TYPE_RAID15: lambda x: x >= 6 and x % 2 == 0, Volume.RAID_TYPE_RAID16: lambda x: x >= 8 and x % 2 == 0, Volume.RAID_TYPE_RAID50: lambda x: x >= 6 and x % 2 == 0, Volume.RAID_TYPE_RAID60: lambda x: x >= 8 and x % 2 == 0, Volume.RAID_TYPE_RAID51: lambda x: x >= 6 and x % 2 == 0, Volume.RAID_TYPE_RAID61: lambda x: x >= 8 and x % 2 == 0, } _RAID_PARITY_DISK_COUNT_FUNC = { Volume.RAID_TYPE_JBOD: lambda x: x, Volume.RAID_TYPE_RAID0: lambda x: x, Volume.RAID_TYPE_RAID1: lambda x: 1, Volume.RAID_TYPE_RAID3: lambda x: x - 1, Volume.RAID_TYPE_RAID4: lambda x: x - 1, Volume.RAID_TYPE_RAID5: lambda x: x - 1, Volume.RAID_TYPE_RAID6: lambda x: x - 2, Volume.RAID_TYPE_RAID10: lambda x: int_div(x, 2), Volume.RAID_TYPE_RAID15: lambda x: int_div(x, 2) - 1, Volume.RAID_TYPE_RAID16: lambda x: int_div(x, 2) - 2, Volume.RAID_TYPE_RAID50: lambda x: x - 2, Volume.RAID_TYPE_RAID60: lambda x: x - 4, Volume.RAID_TYPE_RAID51: lambda x: int_div(x, 2) - 1, Volume.RAID_TYPE_RAID61: lambda x: int_div(x, 2) - 2, } @staticmethod def data_disk_count(raid_type, disk_count): """ Return a integer indicating how many disks should be used as real data(not mirrored or parity) disks. Treating RAID 5 and 6 using fixed parity disk. """ if raid_type not in list(PoolRAID._RAID_DISK_CHK.keys()): raise LsmError( ErrorNumber.PLUGIN_BUG, "data_disk_count(): Got unsupported raid type(%d)" % raid_type) if PoolRAID._RAID_DISK_CHK[raid_type](disk_count) is False: raise LsmError( ErrorNumber.PLUGIN_BUG, "data_disk_count(): Illegal disk count" "(%d) for raid type(%d)" % (disk_count, raid_type)) return PoolRAID._RAID_PARITY_DISK_COUNT_FUNC[raid_type](disk_count) class BackStore(object): VERSION = "4.1" VERSION_SIGNATURE = 'LSM_SIMULATOR_DATA_%s_%s' % (VERSION, md5(VERSION)) JOB_DEFAULT_DURATION = 1 JOB_DATA_TYPE_VOL = 1 JOB_DATA_TYPE_FS = 2 JOB_DATA_TYPE_FS_SNAP = 3 SYS_ID = "sim-01" SYS_NAME = "LSM simulated storage plug-in" BLK_SIZE = 512 DEFAULT_STRIP_SIZE = 128 * 1024 # 128 KiB SYS_MODE = System.MODE_HARDWARE_RAID DEFAULT_WRITE_CACHE_POLICY = Volume.WRITE_CACHE_POLICY_AUTO DEFAULT_READ_CACHE_POLICY = Volume.READ_CACHE_POLICY_ENABLED DEFAULT_PHYSICAL_DISK_CACHE = Volume.PHYSICAL_DISK_CACHE_DISABLED _DEFAULT_READ_CACHE_PCT = 10 _LIST_SPLITTER = '#' _ID_FMT_LEN = 5 SUPPORTED_VCR_RAID_TYPES = [ Volume.RAID_TYPE_RAID0, Volume.RAID_TYPE_RAID1, Volume.RAID_TYPE_RAID5, Volume.RAID_TYPE_RAID6, Volume.RAID_TYPE_RAID10, Volume.RAID_TYPE_RAID50, Volume.RAID_TYPE_RAID60] SUPPORTED_VCR_STRIP_SIZES = [ 8 * 1024, 16 * 1024, 32 * 1024, 64 * 1024, 128 * 1024, 256 * 1024, 512 * 1024, 1024 * 1024] def __init__(self, statefile, timeout): if not os.path.exists(statefile): os.close(os.open(statefile, os.O_WRONLY | os.O_CREAT)) # Due to umask, os.open() created file migt not be 666 permission. os.chmod(statefile, 0o666) self.statefile = statefile self.lastrowid = None self.sql_conn = sqlite3.connect( statefile, timeout=int(int_div(timeout, 1000)), isolation_level="IMMEDIATE") self.sql_conn.row_factory = _dict_factory # Create tables no matter exist or not. No lock required. sql_cmd = "PRAGMA foreign_keys = ON;\n" sql_cmd += \ """ CREATE TABLE systems ( id TEXT PRIMARY KEY, name TEXT NOT NULL, status INTEGER NOT NULL, status_info TEXT, read_cache_pct INTEGER, version TEXT NOT NULL); """ # version: hold the signature of data sql_cmd += \ """ CREATE TABLE tgts ( id INTEGER PRIMARY KEY, port_type INTEGER NOT NULL, service_address TEXT NOT NULL, network_address TEXT NOT NULL, physical_address TEXT NOT NULL, physical_name TEXT NOT NULL); """ sql_cmd += \ """ CREATE TABLE pools ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, status INTEGER NOT NULL, status_info TEXT, element_type INTEGER NOT NULL, unsupported_actions INTEGER, raid_type INTEGER NOT NULL, parent_pool_id INTEGER, member_type INTEGER, strip_size INTEGER, total_space LONG); """ # parent_pool_id: # Indicate this pool is allocated from # other pool # total_space: # is only for sub-pool \pool from pool) sql_cmd += \ """ CREATE TABLE disks ( id INTEGER PRIMARY KEY, total_space LONG NOT NULL, disk_type INTEGER NOT NULL, status INTEGER NOT NULL, disk_prefix TEXT NOT NULL, location TEXT NOT NULL, owner_pool_id INTEGER, role TEXT, vpd83 TEXT, rpm INTEGER, link_type INTEGER, FOREIGN KEY(owner_pool_id) REFERENCES pools(id) ON DELETE SET DEFAULT); """ # owner_pool_id: # Indicate this disk is used to assemble a pool sql_cmd += \ """ CREATE TABLE volumes ( id INTEGER PRIMARY KEY, vpd83 TEXT NOT NULL, name TEXT UNIQUE NOT NULL, total_space LONG NOT NULL, consumed_size LONG NOT NULL, admin_state INTEGER, is_hw_raid_vol INTEGER, write_cache_policy INTEGER NOT NULL, read_cache_policy INTEGER NOT NULL, phy_disk_cache INTEGER NOT NULL, pool_id INTEGER NOT NULL, FOREIGN KEY(pool_id) REFERENCES pools(id) ON DELETE CASCADE); """ # consumed_size: # Reserved for future thinp support. # is_hw_raid_vol: # Once its volume deleted, pool will be delete also. # For HW RAID simulation only. sql_cmd += \ """ CREATE TABLE ags ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL); """ sql_cmd += \ """ CREATE TABLE inits ( id TEXT UNIQUE NOT NULL, init_type INTEGER NOT NULL, owner_ag_id INTEGER NOT NULL, FOREIGN KEY(owner_ag_id) REFERENCES ags(id) ON DELETE CASCADE); """ sql_cmd += \ """ CREATE TABLE vol_masks ( vol_id INTEGER NOT NULL, ag_id INTEGER NOT NULL, FOREIGN KEY(vol_id) REFERENCES volumes(id) ON DELETE CASCADE, FOREIGN KEY(ag_id) REFERENCES ags(id) ON DELETE CASCADE); """ sql_cmd += \ """ CREATE TABLE vol_reps ( rep_type INTEGER, src_vol_id INTEGER NOT NULL, dst_vol_id INTEGER NOT NULL, FOREIGN KEY(src_vol_id) REFERENCES volumes(id) ON DELETE CASCADE, FOREIGN KEY(dst_vol_id) REFERENCES volumes(id) ON DELETE CASCADE); """ sql_cmd += \ """ CREATE TABLE fss ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, total_space LONG NOT NULL, consumed_size LONG NOT NULL, free_space LONG, pool_id INTEGER NOT NULL, FOREIGN KEY(pool_id) REFERENCES pools(id) ON DELETE CASCADE); """ sql_cmd += \ """ CREATE TABLE fs_snaps ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, fs_id INTEGER NOT NULL, timestamp LONG NOT NULL, FOREIGN KEY(fs_id) REFERENCES fss(id) ON DELETE CASCADE); """ sql_cmd += \ """ CREATE TABLE fs_clones ( src_fs_id INTEGER NOT NULL, dst_fs_id INTEGER NOT NULL, FOREIGN KEY(src_fs_id) REFERENCES fss(id) ON DELETE CASCADE, FOREIGN KEY(dst_fs_id) REFERENCES fss(id) ON DELETE CASCADE); """ sql_cmd += \ """ CREATE TABLE exps ( id INTEGER PRIMARY KEY, fs_id INTEGER NOT NULL, exp_path TEXT UNIQUE NOT NULL, auth_type TEXT, anon_uid INTEGER, anon_gid INTEGER, options TEXT, FOREIGN KEY(fs_id) REFERENCES fss(id) ON DELETE CASCADE); """ sql_cmd += \ """ CREATE TABLE exp_root_hosts ( host TEXT NOT NULL, exp_id INTEGER NOT NULL, FOREIGN KEY(exp_id) REFERENCES exps(id) ON DELETE CASCADE); """ sql_cmd += \ """ CREATE TABLE exp_rw_hosts ( host TEXT NOT NULL, exp_id INTEGER NOT NULL, FOREIGN KEY(exp_id) REFERENCES exps(id) ON DELETE CASCADE); """ sql_cmd += \ """ CREATE TABLE exp_ro_hosts ( host TEXT NOT NULL, exp_id INTEGER NOT NULL, FOREIGN KEY(exp_id) REFERENCES exps(id) ON DELETE CASCADE); """ sql_cmd += \ """ CREATE TABLE jobs ( id INTEGER PRIMARY KEY, duration REAL NOT NULL, timestamp TEXT NOT NULL, data_type INTEGER, data_id INTEGER); """ sql_cmd += \ """ CREATE TABLE batteries ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, type INTEGER NOT NULL, status INTEGER NOT NULL); """ # Create views, SUBSTR() used below is alternative way of PRINTF() # which only exists on sqlite 3.8+ while RHEL6 or Ubuntu 12.04 ships # older version. sql_cmd += \ """ CREATE VIEW pools_view AS SELECT pool0.id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool0.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id, pool0.name, pool0.status, pool0.status_info, pool0.element_type, pool0.unsupported_actions, pool0.raid_type, pool0.member_type, pool0.parent_pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool0.parent_pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) parent_lsm_pool_id, pool0.strip_size, pool1.total_space total_space, pool1.total_space - pool2.vol_consumed_size - pool3.fs_consumed_size - pool4.sub_pool_consumed_size free_space, pool1.data_disk_count, pool5.disk_count FROM pools pool0 LEFT JOIN ( SELECT pool.id, ifnull(pool.total_space, ifnull(SUM(disk.total_space), 0)) total_space, COUNT(disk.id) data_disk_count FROM pools pool LEFT JOIN disks disk ON pool.id = disk.owner_pool_id AND disk.role = 'DATA' GROUP BY pool.id ) pool1 ON pool0.id = pool1.id LEFT JOIN ( SELECT pool.id, ifnull(SUM(volume.consumed_size), 0) vol_consumed_size FROM pools pool LEFT JOIN volumes volume ON volume.pool_id = pool.id GROUP BY pool.id ) pool2 ON pool0.id = pool2.id LEFT JOIN ( SELECT pool.id, ifnull(SUM(fs.consumed_size), 0) fs_consumed_size FROM pools pool LEFT JOIN fss fs ON fs.pool_id = pool.id GROUP BY pool.id ) pool3 ON pool0.id = pool3.id LEFT JOIN ( SELECT pool.id, ifnull(SUM(sub_pool.total_space), 0) sub_pool_consumed_size FROM pools pool LEFT JOIN pools sub_pool ON sub_pool.parent_pool_id = pool.id GROUP BY pool.id ) pool4 ON pool0.id = pool4.id LEFT JOIN ( SELECT pool.id, COUNT(disk.id) disk_count FROM pools pool LEFT JOIN disks disk ON pool.id = disk.owner_pool_id GROUP BY pool.id ) pool5 ON pool0.id = pool5.id GROUP BY pool0.id; """ sql_cmd += \ """ CREATE VIEW tgts_view AS SELECT id, 'TGT_PORT_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_tgt_id, port_type, service_address, network_address, physical_address, physical_name FROM tgts; """ sql_cmd += \ """ CREATE VIEW disks_view AS SELECT id, 'DISK_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_disk_id, disk_prefix || '_' || id name, total_space, disk_type, role, status, vpd83, rpm, link_type, location, owner_pool_id FROM disks; """ sql_cmd += \ """ CREATE VIEW volumes_view AS SELECT id, 'VOL_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_vol_id, vpd83, name, total_space, consumed_size, admin_state, is_hw_raid_vol, write_cache_policy, read_cache_policy, phy_disk_cache, pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id FROM volumes; """ sql_cmd += \ """ CREATE VIEW fss_view AS SELECT id, 'FS_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_id, name, total_space, consumed_size, free_space, pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id FROM fss; """ sql_cmd += \ """ CREATE VIEW bats_view AS SELECT id, 'BAT_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_bat_id, name, type, status FROM batteries; """ sql_cmd += \ """ CREATE VIEW fs_snaps_view AS SELECT id, 'FS_SNAP_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_snap_id, name, timestamp, fs_id, 'FS_ID_' || SUBSTR('{ID_PADDING}' || fs_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_id FROM fs_snaps; """ sql_cmd += \ """ CREATE VIEW volumes_by_ag_view AS SELECT vol.id, 'VOL_ID_' || SUBSTR('{ID_PADDING}' || vol.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_vol_id, vol.vpd83, vol.name, vol.total_space, vol.consumed_size, vol.pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || vol.pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id, vol.admin_state, vol.is_hw_raid_vol, vol_mask.ag_id ag_id, vol.write_cache_policy, vol.read_cache_policy, vol.phy_disk_cache FROM volumes vol LEFT JOIN vol_masks vol_mask ON vol_mask.vol_id = vol.id; """ sql_cmd += \ """ CREATE VIEW ags_view AS SELECT ag.id, 'AG_ID_' || SUBSTR('{ID_PADDING}' || ag.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_ag_id, ag.name, CASE WHEN count(DISTINCT init.init_type) = 1 THEN init.init_type WHEN count(DISTINCT init.init_type) = 2 THEN {AG_INIT_TYPE_MIXED} ELSE {AG_INIT_TYPE_UNKNOWN} END init_type, group_concat(init.id, '{SPLITTER}') init_ids_str FROM ags ag LEFT JOIN inits init ON ag.id = init.owner_ag_id GROUP BY ag.id ORDER BY init.init_type; """ sql_cmd += \ """ CREATE VIEW ags_by_vol_view AS SELECT ag_new.id, 'AG_ID_' || SUBSTR('{ID_PADDING}' || ag_new.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_ag_id, ag_new.name, ag_new.init_type, ag_new.init_ids_str, vol_mask.vol_id vol_id FROM ( SELECT ag.id, ag.name, CASE WHEN count(DISTINCT init.init_type) = 1 THEN init.init_type WHEN count(DISTINCT init.init_type) = 2 THEN {AG_INIT_TYPE_MIXED} ELSE {AG_INIT_TYPE_UNKNOWN} END init_type, group_concat(init.id, '{SPLITTER}') init_ids_str FROM ags ag LEFT JOIN inits init ON ag.id = init.owner_ag_id GROUP BY ag.id ORDER BY init.init_type ) ag_new LEFT JOIN vol_masks vol_mask ON vol_mask.ag_id = ag_new.id ; """ sql_cmd += \ """ CREATE VIEW exps_view AS SELECT exp.id, 'EXP_ID_' || SUBSTR('{ID_PADDING}' || exp.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_exp_id, exp.fs_id, 'FS_ID_' || SUBSTR('{ID_PADDING}' || exp.fs_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_id, exp.exp_path, exp.auth_type, exp.anon_uid, exp.anon_gid, exp.options, exp2.exp_root_hosts_str, exp3.exp_rw_hosts_str, exp4.exp_ro_hosts_str FROM exps exp LEFT JOIN ( SELECT exp_t2.id, group_concat( exp_root_host.host, '{SPLITTER}') exp_root_hosts_str FROM exps exp_t2 LEFT JOIN exp_root_hosts exp_root_host ON exp_t2.id = exp_root_host.exp_id GROUP BY exp_t2.id ) exp2 ON exp.id = exp2.id LEFT JOIN ( SELECT exp_t3.id, group_concat( exp_rw_host.host, '{SPLITTER}') exp_rw_hosts_str FROM exps exp_t3 LEFT JOIN exp_rw_hosts exp_rw_host ON exp_t3.id = exp_rw_host.exp_id GROUP BY exp_t3.id ) exp3 ON exp.id = exp3.id LEFT JOIN ( SELECT exp_t4.id, group_concat( exp_ro_host.host, '{SPLITTER}') exp_ro_hosts_str FROM exps exp_t4 LEFT JOIN exp_ro_hosts exp_ro_host ON exp_t4.id = exp_ro_host.exp_id GROUP BY exp_t4.id ) exp4 ON exp.id = exp4.id GROUP BY exp.id; ; """ sql_cmd = sql_cmd.format(**{ 'ID_PADDING': '0' * BackStore._ID_FMT_LEN, 'ID_FMT_LEN': BackStore._ID_FMT_LEN, 'AG_INIT_TYPE_MIXED': AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED, 'AG_INIT_TYPE_UNKNOWN': AccessGroup.INIT_TYPE_UNKNOWN, 'SPLITTER': BackStore._LIST_SPLITTER, }) sql_cur = self.sql_conn.cursor() try: sql_cur.executescript(sql_cmd) except sqlite3.OperationalError as sql_error: if 'already exists' in str(sql_error): pass else: raise sql_error except sqlite3.DatabaseError as sql_error: raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Stored simulator state incompatible with " "simulator, please move or delete %s" % self.statefile) def _check_version(self): sim_syss = self.sim_syss() if len(sim_syss) == 0 or not sim_syss[0]: return False else: if 'version' in sim_syss[0].keys() and \ sim_syss[0]['version'] == BackStore.VERSION_SIGNATURE: return True raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Stored simulator state incompatible with " "simulator, please move or delete %s" % self.statefile) def check_version_and_init(self): """ Raise error if version not match. If empty database found, initiate. """ # The complex lock workflow is all caused by python sqlite3 do # autocommit for "CREATE TABLE" command. self.trans_begin() if self._check_version(): self.trans_commit() return else: self._data_add( 'systems', { 'id': BackStore.SYS_ID, 'name': BackStore.SYS_NAME, 'status': System.STATUS_OK, 'status_info': "", 'version': BackStore.VERSION_SIGNATURE, 'read_cache_pct': BackStore._DEFAULT_READ_CACHE_PCT }) size_bytes_2t = size_human_2_size_bytes('2TiB') size_bytes_512g = size_human_2_size_bytes('512GiB') # Add 2 SATA disks(2TiB) pool_1_disks = [] for i in range(0, 2): self._data_add( 'disks', { 'disk_prefix': "2TiB SATA Disk", 'total_space': size_bytes_2t, 'disk_type': Disk.TYPE_SATA, 'status': Disk.STATUS_OK, 'vpd83': _random_vpd(), 'rpm': 7200, 'link_type': Disk.LINK_TYPE_ATA, 'location': "Port: %d Box: 1 Bay: 1" % i, }) pool_1_disks.append(self.lastrowid) test_pool_disks = [] # Add 6 SAS disks(2TiB) for i in range(0, 6): self._data_add( 'disks', { 'disk_prefix': "2TiB SAS Disk", 'total_space': size_bytes_2t, 'disk_type': Disk.TYPE_SAS, 'status': Disk.STATUS_OK, 'vpd83': _random_vpd(), 'rpm': 15000, 'link_type': Disk.LINK_TYPE_SAS, 'location': "Port: %d Box: 1 Bay: 2" % i, }) if len(test_pool_disks) < 2: test_pool_disks.append(self.lastrowid) ssd_pool_disks = [] # Add 5 SATA SSD disks(512GiB) for i in range(0, 5): self._data_add( 'disks', { 'disk_prefix': "512GiB SSD Disk", 'total_space': size_bytes_512g, 'disk_type': Disk.TYPE_SSD, 'status': Disk.STATUS_OK, 'vpd83': _random_vpd(), 'rpm': Disk.RPM_NON_ROTATING_MEDIUM, 'link_type': Disk.LINK_TYPE_ATA, 'location': "Port: %d Box: 1 Bay: 3" % i, }) if len(ssd_pool_disks) < 2: ssd_pool_disks.append(self.lastrowid) # Add 7 SAS SSD disks(2TiB) for i in range(0, 7): self._data_add( 'disks', { 'disk_prefix': "2TiB SSD Disk", 'total_space': size_bytes_2t, 'disk_type': Disk.TYPE_SSD, 'status': Disk.STATUS_OK, 'vpd83': _random_vpd(), 'rpm': Disk.RPM_NON_ROTATING_MEDIUM, 'link_type': Disk.LINK_TYPE_SAS, 'location': "Port: %d Box: 1 Bay: 4" % i, }) pool_1_id = self.sim_pool_create_from_disk( name='Pool 1', raid_type=Volume.RAID_TYPE_RAID1, sim_disk_ids=pool_1_disks, element_type=Pool.ELEMENT_TYPE_POOL | Pool.ELEMENT_TYPE_FS | Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_DELTA | Pool.ELEMENT_TYPE_SYS_RESERVED, unsupported_actions=Pool.UNSUPPORTED_VOLUME_GROW | Pool.UNSUPPORTED_VOLUME_SHRINK) self.sim_pool_create_sub_pool( name='Pool 2(sub pool of Pool 1)', parent_pool_id=pool_1_id, element_type=Pool.ELEMENT_TYPE_FS | Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_DELTA, size=size_bytes_512g) self.sim_pool_create_from_disk( name='Pool 3', raid_type=Volume.RAID_TYPE_RAID1, sim_disk_ids=ssd_pool_disks, element_type=Pool.ELEMENT_TYPE_FS | Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_DELTA) self.sim_pool_create_from_disk( name='lsm_test_aggr', element_type=Pool.ELEMENT_TYPE_FS | Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_DELTA, raid_type=Volume.RAID_TYPE_RAID0, sim_disk_ids=test_pool_disks) self._data_add( 'tgts', { 'port_type': TargetPort.TYPE_FC, 'service_address': '50:0a:09:86:99:4b:8d:c5', 'network_address': '50:0a:09:86:99:4b:8d:c5', 'physical_address': '50:0a:09:86:99:4b:8d:c5', 'physical_name': 'FC_a_0b', }) self._data_add( 'tgts', { 'port_type': TargetPort.TYPE_FCOE, 'service_address': '50:0a:09:86:99:4b:8d:c6', 'network_address': '50:0a:09:86:99:4b:8d:c6', 'physical_address': '50:0a:09:86:99:4b:8d:c6', 'physical_name': 'FCoE_b_0c', }) self._data_add( 'tgts', { 'port_type': TargetPort.TYPE_ISCSI, 'service_address': 'iqn.1986-05.com.example:sim-tgt-03', 'network_address': 'sim-iscsi-tgt-3.example.com:3260', 'physical_address': 'a4:4e:31:47:f4:e0', 'physical_name': 'iSCSI_c_0d', }) self._data_add( 'tgts', { 'port_type': TargetPort.TYPE_ISCSI, 'service_address': 'iqn.1986-05.com.example:sim-tgt-03', 'network_address': '10.0.0.1:3260', 'physical_address': 'a4:4e:31:47:f4:e1', 'physical_name': 'iSCSI_c_0e', }) self._data_add( 'tgts', { 'port_type': TargetPort.TYPE_ISCSI, 'service_address': 'iqn.1986-05.com.example:sim-tgt-03', 'network_address': '[2001:470:1f09:efe:a64e:31ff::1]:3260', 'physical_address': 'a4:4e:31:47:f4:e1', 'physical_name': 'iSCSI_c_0e', }) self._data_add( 'batteries', { 'name': 'Battery SIMB01, 8000 mAh, 05 March 2016', 'type': Battery.TYPE_CHEMICAL, 'status': Battery.STATUS_OK, }) self._data_add( 'batteries', { 'name': 'Capacitor SIMC01, 500 J, 05 March 2016', 'type': Battery.TYPE_CAPACITOR, 'status': Battery.STATUS_OK, }) self.trans_commit() return def _sql_exec(self, sql_cmd): """ Execute sql command and get all output. """ sql_cur = self.sql_conn.cursor() sql_cur.execute(sql_cmd) self.lastrowid = sql_cur.lastrowid return sql_cur.fetchall() def _get_table(self, table_name): sql_cmd = "SELECT * FROM %s" % table_name return self._sql_exec(sql_cmd) def trans_begin(self): self.sql_conn.execute("BEGIN IMMEDIATE TRANSACTION;") def trans_commit(self): self.sql_conn.commit() def trans_rollback(self): self.sql_conn.rollback() def _data_add(self, table_name, data_dict): keys = list(data_dict.keys()) values = ['' if v is None else str(v) for v in list(data_dict.values())] sql_cmd = "INSERT INTO %s (%s) VALUES (%s);" % \ (table_name, "'%s'" % ("', '".join(keys)), "'%s'" % ("', '".join(values))) self._sql_exec(sql_cmd) def _data_find(self, table, condition, flag_unique=False): sql_cmd = "SELECT * FROM %s WHERE %s" % (table, condition) sim_datas = self._sql_exec(sql_cmd) if flag_unique: if len(sim_datas) == 0: return None elif len(sim_datas) == 1: return sim_datas[0] else: raise LsmError( ErrorNumber.PLUGIN_BUG, "_data_find(): Got non-unique data: %s" % locals()) else: return sim_datas def _data_update(self, table, data_id, column_name, value): if value is None: sql_cmd = "UPDATE %s SET %s=NULL WHERE id='%s'" % \ (table, column_name, data_id) else: sql_cmd = "UPDATE %s SET %s='%s' WHERE id='%s'" % \ (table, column_name, value, data_id) self._sql_exec(sql_cmd) def _data_delete(self, table, condition): sql_cmd = "DELETE FROM %s WHERE %s;" % (table, condition) self._sql_exec(sql_cmd) def sim_job_create(self, job_data_type=None, data_id=None): """ Return a job id(Integer) """ self._data_add( "jobs", { "duration": os.getenv( "LSM_SIM_TIME", BackStore.JOB_DEFAULT_DURATION), "timestamp": time.time(), "data_type": job_data_type, "data_id": data_id, }) return self.lastrowid def sim_job_delete(self, sim_job_id): self._data_delete('jobs', 'id="%s"' % sim_job_id) def sim_job_status(self, sim_job_id): """ Return (progress, data_type, data) tuple. progress is the integer of percent. """ sim_job = self._data_find('jobs', 'id=%s' % sim_job_id, flag_unique=True) if sim_job is None: raise LsmError( ErrorNumber.NOT_FOUND_JOB, "Job not found") progress = int( (time.time() - float(sim_job['timestamp'])) / sim_job['duration'] * 100) data = None data_type = None if progress < 0: progress = 0 if progress >= 100: progress = 100 if sim_job['data_type'] == BackStore.JOB_DATA_TYPE_VOL: data = self.sim_vol_of_id(sim_job['data_id']) data_type = sim_job['data_type'] elif sim_job['data_type'] == BackStore.JOB_DATA_TYPE_FS: data = self.sim_fs_of_id(sim_job['data_id']) data_type = sim_job['data_type'] elif sim_job['data_type'] == BackStore.JOB_DATA_TYPE_FS_SNAP: data = self.sim_fs_snap_of_id(sim_job['data_id']) data_type = sim_job['data_type'] return (progress, data_type, data) def sim_syss(self): """ Return a list of sim_sys dict. """ return self._get_table('systems') def lsm_disk_ids_of_pool(self, sim_pool_id): return list( d['lsm_disk_id'] for d in self._data_find( 'disks_view', 'owner_pool_id="%s"' % sim_pool_id)) def sim_disks(self): """ Return a list of sim_disk dict. """ return self._get_table('disks_view') def sim_pools(self): """ Return a list of sim_pool dict. """ return self._get_table('pools_view') def sim_pool_of_id(self, sim_pool_id): return self._sim_data_of_id( "pools_view", sim_pool_id, ErrorNumber.NOT_FOUND_POOL, "Pool") def sim_pool_create_from_disk(self, name, sim_disk_ids, raid_type, element_type, unsupported_actions=0, strip_size=0): if strip_size == 0: strip_size = BackStore.DEFAULT_STRIP_SIZE if raid_type == Volume.RAID_TYPE_RAID1 or \ raid_type == Volume.RAID_TYPE_JBOD: strip_size = BackStore.BLK_SIZE self._data_add( 'pools', { 'name': name, 'status': Pool.STATUS_OK, 'status_info': '', 'element_type': element_type, 'unsupported_actions': unsupported_actions, 'raid_type': raid_type, 'member_type': Pool.MEMBER_TYPE_DISK, 'strip_size': strip_size, }) data_disk_count = PoolRAID.data_disk_count( raid_type, len(sim_disk_ids)) # update disk owner sim_pool_id = self.lastrowid for sim_disk_id in sim_disk_ids[:data_disk_count]: self._data_update( 'disks', sim_disk_id, 'owner_pool_id', sim_pool_id) self._data_update( 'disks', sim_disk_id, 'role', 'DATA') for sim_disk_id in sim_disk_ids[data_disk_count:]: self._data_update( 'disks', sim_disk_id, 'owner_pool_id', sim_pool_id) self._data_update( 'disks', sim_disk_id, 'role', 'PARITY') return sim_pool_id def sim_pool_create_sub_pool(self, name, parent_pool_id, size, element_type, unsupported_actions=0): self._data_add( 'pools', { 'name': name, 'status': Pool.STATUS_OK, 'status_info': '', 'element_type': element_type, 'unsupported_actions': unsupported_actions, 'raid_type': Volume.RAID_TYPE_OTHER, 'member_type': Pool.MEMBER_TYPE_POOL, 'parent_pool_id': parent_pool_id, 'total_space': size, }) return self.lastrowid def sim_pool_disks_count(self, sim_pool_id): return self._sql_exec( "SELECT COUNT(id) FROM disks WHERE owner_pool_id=%s;" % sim_pool_id)[0][0] def sim_pool_data_disks_count(self, sim_pool_id=None): return self._sql_exec( "SELECT COUNT(id) FROM disks WHERE " "owner_pool_id=%s and role='DATA';" % sim_pool_id)[0][0] def sim_vols(self, sim_ag_id=None): """ Return a list of sim_vol dict. """ if sim_ag_id: return self._data_find( 'volumes_by_ag_view', 'ag_id=%s' % sim_ag_id) else: return self._get_table('volumes_view') def _sim_data_of_id(self, table_name, data_id, lsm_error_no, data_name): sim_data = self._data_find( table_name, 'id=%s' % data_id, flag_unique=True) if sim_data is None: if lsm_error_no: raise LsmError( lsm_error_no, "%s not found" % data_name) else: return None return sim_data def sim_vol_of_id(self, sim_vol_id): """ Return sim_vol if found. Raise error if not found. """ return self._sim_data_of_id( "volumes_view", sim_vol_id, ErrorNumber.NOT_FOUND_VOLUME, "Volume") def _check_pool_free_space(self, sim_pool_id, size_bytes): sim_pool = self.sim_pool_of_id(sim_pool_id) if (sim_pool['free_space'] < size_bytes): raise LsmError(ErrorNumber.NOT_ENOUGH_SPACE, "Insufficient space in pool") @staticmethod def _block_rounding(size_bytes): return (size_bytes + BackStore.BLK_SIZE - 1) // \ BackStore.BLK_SIZE * BackStore.BLK_SIZE def sim_vol_create(self, name, size_bytes, sim_pool_id, is_hw_raid_vol=0): size_bytes = BackStore._block_rounding(size_bytes) self._check_pool_free_space(sim_pool_id, size_bytes) sim_vol = dict() sim_vol['vpd83'] = _random_vpd() sim_vol['name'] = name sim_vol['pool_id'] = sim_pool_id sim_vol['total_space'] = size_bytes sim_vol['consumed_size'] = size_bytes sim_vol['admin_state'] = Volume.ADMIN_STATE_ENABLED sim_vol['is_hw_raid_vol'] = is_hw_raid_vol sim_vol['write_cache_policy'] = BackStore.DEFAULT_WRITE_CACHE_POLICY sim_vol['read_cache_policy'] = BackStore.DEFAULT_READ_CACHE_POLICY sim_vol['phy_disk_cache'] = BackStore.DEFAULT_PHYSICAL_DISK_CACHE try: self._data_add("volumes", sim_vol) except sqlite3.IntegrityError as sql_error: raise LsmError( ErrorNumber.NAME_CONFLICT, "Name '%s' is already in use by other volume" % name) return self.lastrowid def sim_vol_delete(self, sim_vol_id): """ This does not check whether volume exist or not. """ # Check existence. sim_vol = self.sim_vol_of_id(sim_vol_id) if self._sim_ag_ids_of_masked_vol(sim_vol_id): raise LsmError( ErrorNumber.IS_MASKED, "Volume is masked to access group") dst_sim_vol_ids = self.dst_sim_vol_ids_of_src(sim_vol_id) if len(dst_sim_vol_ids) >= 1: for dst_sim_vol_id in dst_sim_vol_ids: if dst_sim_vol_id != sim_vol_id: # Don't raise error on volume internal replication. raise LsmError( ErrorNumber.HAS_CHILD_DEPENDENCY, "Requested volume has child dependency") if sim_vol['is_hw_raid_vol']: # Reset disk roles for d in self._data_find('disks_view', 'owner_pool_id="%s"' % sim_vol["pool_id"]): self._data_update("disks", d["id"], 'role', None) # Delete the parent pool instead if found a HW RAID volume. self._data_delete("pools", 'id="%s"' % sim_vol['pool_id']) else: self._data_delete("volumes", 'id="%s"' % sim_vol_id) def sim_vol_mask(self, sim_vol_id, sim_ag_id): self.sim_vol_of_id(sim_vol_id) self.sim_ag_of_id(sim_ag_id) exist_mask = self._data_find( 'vol_masks', 'ag_id="%s" AND vol_id="%s"' % (sim_ag_id, sim_vol_id)) if exist_mask: raise LsmError( ErrorNumber.NO_STATE_CHANGE, "Volume is already masked to requested access group") self._data_add( "vol_masks", {'ag_id': sim_ag_id, 'vol_id': sim_vol_id}) return None def sim_vol_unmask(self, sim_vol_id, sim_ag_id): self.sim_vol_of_id(sim_vol_id) self.sim_ag_of_id(sim_ag_id) condition = 'ag_id="%s" AND vol_id="%s"' % (sim_ag_id, sim_vol_id) exist_mask = self._data_find('vol_masks', condition) if exist_mask: self._data_delete('vol_masks', condition) else: raise LsmError( ErrorNumber.NO_STATE_CHANGE, "Volume is not masked to requested access group") return None def _sim_vol_ids_of_masked_ag(self, sim_ag_id): return list( m['vol_id'] for m in self._data_find( 'vol_masks', 'ag_id="%s"' % sim_ag_id)) def _sim_ag_ids_of_masked_vol(self, sim_vol_id): return list( m['ag_id'] for m in self._data_find( 'vol_masks', 'vol_id="%s"' % sim_vol_id)) def sim_vol_resize(self, sim_vol_id, new_size_bytes): new_size_bytes = BackStore._block_rounding(new_size_bytes) sim_vol = self.sim_vol_of_id(sim_vol_id) if sim_vol['total_space'] == new_size_bytes: raise LsmError( ErrorNumber.NO_STATE_CHANGE, "Volume size is identical to requested") sim_pool = self.sim_pool_of_id(sim_vol['pool_id']) increment = new_size_bytes - sim_vol['total_space'] if increment > 0: if sim_pool['unsupported_actions'] & Pool.UNSUPPORTED_VOLUME_GROW: raise LsmError( ErrorNumber.NO_SUPPORT, "Requested pool does not allow volume size grow") if sim_pool['free_space'] < increment: raise LsmError( ErrorNumber.NOT_ENOUGH_SPACE, "Insufficient space in pool") elif sim_pool['unsupported_actions'] & Pool.UNSUPPORTED_VOLUME_SHRINK: raise LsmError( ErrorNumber.NO_SUPPORT, "Requested pool does not allow volume size grow") # TODO(Gris Ge): If a volume is in a replication relationship, resize # should be handled properly. self._data_update( 'volumes', sim_vol_id, "total_space", new_size_bytes) self._data_update( 'volumes', sim_vol_id, "consumed_size", new_size_bytes) def dst_sim_vol_ids_of_src(self, src_sim_vol_id): """ Return a list of dst_vol_id for provided source volume ID. """ self.sim_vol_of_id(src_sim_vol_id) return list( d['dst_vol_id'] for d in self._data_find( 'vol_reps', 'src_vol_id="%s"' % src_sim_vol_id)) def sim_vol_replica(self, src_sim_vol_id, dst_sim_vol_id, rep_type, blk_ranges=None): self.sim_vol_of_id(src_sim_vol_id) self.sim_vol_of_id(dst_sim_vol_id) # If we are replicating with ourselves we need not track it. if src_sim_vol_id == dst_sim_vol_id: return # A bitwise copy does not imply a replicated relation ship and thus # doesn't require anything to separate a src and destination volume. if rep_type == Volume.REPLICATE_COPY: return cur_src_sim_vol_ids = list( r['src_vol_id'] for r in self._data_find( 'vol_reps', 'dst_vol_id="%s"' % dst_sim_vol_id)) if len(cur_src_sim_vol_ids) == 1: # We already have a relationship, do not need to add more return # Add the relationship self._data_add( 'vol_reps', { 'src_vol_id': src_sim_vol_id, 'dst_vol_id': dst_sim_vol_id, 'rep_type': rep_type, }) # No need to trace block range due to lack of query method. def sim_vol_src_replica_break(self, src_sim_vol_id): if not self.dst_sim_vol_ids_of_src(src_sim_vol_id): raise LsmError( ErrorNumber.NO_STATE_CHANGE, "Provided volume is not a replication source") self._data_delete( 'vol_reps', 'src_vol_id="%s"' % src_sim_vol_id) def sim_vol_state_change(self, sim_vol_id, new_admin_state): sim_vol = self.sim_vol_of_id(sim_vol_id) if sim_vol['admin_state'] == new_admin_state: raise LsmError( ErrorNumber.NO_STATE_CHANGE, "Volume admin state is identical to requested") self._data_update( 'volumes', sim_vol_id, "admin_state", new_admin_state) @staticmethod def _sim_ag_format(sim_ag): """ Update 'init_type' and 'init_ids' of sim_ag """ sim_ag['init_ids'] = sim_ag['init_ids_str'].split( BackStore._LIST_SPLITTER) del sim_ag['init_ids_str'] return sim_ag def sim_ags(self, sim_vol_id=None): if sim_vol_id: sim_ags = self._data_find( 'ags_by_vol_view', 'vol_id=%s' % sim_vol_id) else: sim_ags = self._get_table('ags_view') return [BackStore._sim_ag_format(a) for a in sim_ags] def _sim_init_create(self, init_type, init_id, sim_ag_id): try: self._data_add( "inits", { 'id': init_id, 'init_type': init_type, 'owner_ag_id': sim_ag_id }) except sqlite3.IntegrityError as sql_error: raise LsmError( ErrorNumber.EXISTS_INITIATOR, "Initiator '%s' is already in use by other access group" % init_id) def iscsi_chap_auth_set(self, init_id, in_user, in_pass, out_user, out_pass): # Currently, there is no API method to query status of iscsi CHAP. return None def sim_ag_create(self, name, init_type, init_id): try: self._data_add("ags", {'name': name}) sim_ag_id = self.lastrowid except sqlite3.IntegrityError as sql_error: raise LsmError( ErrorNumber.NAME_CONFLICT, "Name '%s' is already in use by other access group" % name) self._sim_init_create(init_type, init_id, sim_ag_id) return sim_ag_id def sim_ag_delete(self, sim_ag_id): self.sim_ag_of_id(sim_ag_id) if self._sim_vol_ids_of_masked_ag(sim_ag_id): raise LsmError( ErrorNumber.IS_MASKED, "Access group has volume masked to") self._data_delete('ags', 'id="%s"' % sim_ag_id) def sim_ag_init_add(self, sim_ag_id, init_id, init_type): sim_ag = self.sim_ag_of_id(sim_ag_id) if init_id in sim_ag['init_ids']: raise LsmError( ErrorNumber.NO_STATE_CHANGE, "Initiator already in access group") if init_type != AccessGroup.INIT_TYPE_ISCSI_IQN and \ init_type != AccessGroup.INIT_TYPE_WWPN: raise LsmError( ErrorNumber.NO_SUPPORT, "Only support iSCSI IQN and WWPN initiator type") self._sim_init_create(init_type, init_id, sim_ag_id) return None def sim_ag_init_delete(self, sim_ag_id, init_id): sim_ag = self.sim_ag_of_id(sim_ag_id) if init_id not in sim_ag['init_ids']: raise LsmError( ErrorNumber.NO_STATE_CHANGE, "Initiator is not in defined access group") if len(sim_ag['init_ids']) == 1: raise LsmError( ErrorNumber.LAST_INIT_IN_ACCESS_GROUP, "Refused to remove the last initiator from access group") self._data_delete('inits', 'id="%s"' % init_id) def sim_ag_of_id(self, sim_ag_id): sim_ag = self._sim_data_of_id( "ags_view", sim_ag_id, ErrorNumber.NOT_FOUND_ACCESS_GROUP, "Access Group") BackStore._sim_ag_format(sim_ag) return sim_ag def sim_fss(self): """ Return a list of sim_fs dict. """ return self._get_table('fss_view') def sim_fs_of_id(self, sim_fs_id, raise_error=True): lsm_error_no = ErrorNumber.NOT_FOUND_FS if not raise_error: lsm_error_no = None return self._sim_data_of_id( "fss_view", sim_fs_id, lsm_error_no, "File System") def sim_fs_create(self, name, size_bytes, sim_pool_id): size_bytes = BackStore._block_rounding(size_bytes) self._check_pool_free_space(sim_pool_id, size_bytes) try: self._data_add( "fss", { 'name': name, 'total_space': size_bytes, 'consumed_size': size_bytes, 'free_space': size_bytes, 'pool_id': sim_pool_id, }) except sqlite3.IntegrityError as sql_error: raise LsmError( ErrorNumber.NAME_CONFLICT, "Name '%s' is already in use by other fs" % name) return self.lastrowid def sim_fs_delete(self, sim_fs_id): self.sim_fs_of_id(sim_fs_id) if self.clone_dst_sim_fs_ids_of_src(sim_fs_id): raise LsmError( ErrorNumber.HAS_CHILD_DEPENDENCY, "Requested file system has child dependency") self._data_delete("fss", 'id="%s"' % sim_fs_id) def sim_fs_resize(self, sim_fs_id, new_size_bytes): new_size_bytes = BackStore._block_rounding(new_size_bytes) sim_fs = self.sim_fs_of_id(sim_fs_id) if sim_fs['total_space'] == new_size_bytes: raise LsmError( ErrorNumber.NO_STATE_CHANGE, "File System size is identical to requested") # TODO(Gris Ge): If a fs is in a clone/snapshot relationship, resize # should be handled properly. sim_pool = self.sim_pool_of_id(sim_fs['pool_id']) if new_size_bytes > sim_fs['total_space'] and \ sim_pool['free_space'] < new_size_bytes - sim_fs['total_space']: raise LsmError( ErrorNumber.NOT_ENOUGH_SPACE, "Insufficient space in pool") self._data_update( 'fss', sim_fs_id, "total_space", new_size_bytes) self._data_update( 'fss', sim_fs_id, "consumed_size", new_size_bytes) self._data_update( 'fss', sim_fs_id, "free_space", new_size_bytes) def sim_fs_snaps(self, sim_fs_id): self.sim_fs_of_id(sim_fs_id) return self._data_find('fs_snaps_view', 'fs_id="%s"' % sim_fs_id) def sim_fs_snap_of_id(self, sim_fs_snap_id, sim_fs_id=None): sim_fs_snap = self._sim_data_of_id( 'fs_snaps_view', sim_fs_snap_id, ErrorNumber.NOT_FOUND_FS_SS, 'File system snapshot') if sim_fs_id and sim_fs_snap['fs_id'] != sim_fs_id: raise LsmError( ErrorNumber.NOT_FOUND_FS_SS, "Defined file system snapshot ID is not belong to requested " "file system") return sim_fs_snap def sim_fs_snap_create(self, sim_fs_id, name): self.sim_fs_of_id(sim_fs_id) try: self._data_add( 'fs_snaps', { 'name': name, 'fs_id': sim_fs_id, 'timestamp': int(time.time()), }) except sqlite3.IntegrityError as sql_error: raise LsmError( ErrorNumber.NAME_CONFLICT, "The name is already used by other file system snapshot") return self.lastrowid def sim_fs_snap_restore(self, sim_fs_id, sim_fs_snap_id, files, restore_files, flag_all_files): # Currently LSM cannot query stauts of this action. # we simply check existence self.sim_fs_of_id(sim_fs_id) if sim_fs_snap_id: self.sim_fs_snap_of_id(sim_fs_snap_id, sim_fs_id) return def sim_fs_snap_delete(self, sim_fs_snap_id, sim_fs_id): self.sim_fs_of_id(sim_fs_id) self.sim_fs_snap_of_id(sim_fs_snap_id, sim_fs_id) self._data_delete('fs_snaps', 'id="%s"' % sim_fs_snap_id) def sim_fs_snap_del_by_fs(self, sim_fs_id): sql_cmd = "DELETE FROM fs_snaps WHERE fs_id='%s';" % sim_fs_id self._sql_exec(sql_cmd) def sim_fs_clone(self, src_sim_fs_id, dst_sim_fs_id, sim_fs_snap_id): self.sim_fs_of_id(src_sim_fs_id) self.sim_fs_of_id(dst_sim_fs_id) if sim_fs_snap_id: # No need to trace state of snap id here due to lack of # query method. # We just check snapshot existence self.sim_fs_snap_of_id(sim_fs_snap_id, src_sim_fs_id) self._data_add( 'fs_clones', { 'src_fs_id': src_sim_fs_id, 'dst_fs_id': dst_sim_fs_id, }) def sim_fs_file_clone(self, sim_fs_id, src_fs_name, dst_fs_name, sim_fs_snap_id): # We don't have API to query file level clone. # Simply check existence self.sim_fs_of_id(sim_fs_id) if sim_fs_snap_id: self.sim_fs_snap_of_id(sim_fs_snap_id, sim_fs_id) return def clone_dst_sim_fs_ids_of_src(self, src_sim_fs_id): """ Return a list of dst_fs_id for provided clone source fs ID. """ self.sim_fs_of_id(src_sim_fs_id) return list( d['dst_fs_id'] for d in self._data_find( 'fs_clones', 'src_fs_id="%s"' % src_sim_fs_id)) def sim_fs_src_clone_break(self, src_sim_fs_id): self._data_delete('fs_clones', 'src_fs_id="%s"' % src_sim_fs_id) def _sim_exp_format(self, sim_exp): for key_name in ['root_hosts', 'rw_hosts', 'ro_hosts']: table_name = "exp_%s_str" % key_name if sim_exp[table_name]: sim_exp[key_name] = sim_exp[table_name].split( BackStore._LIST_SPLITTER) else: sim_exp[key_name] = [] del sim_exp[table_name] return sim_exp def sim_exps(self): return list(self._sim_exp_format(e) for e in self._get_table('exps_view')) def sim_exp_of_id(self, sim_exp_id): return self._sim_exp_format( self._sim_data_of_id('exps_view', sim_exp_id, ErrorNumber.NOT_FOUND_NFS_EXPORT, 'NFS Export')) def sim_exp_create(self, sim_fs_id, exp_path, root_hosts, rw_hosts, ro_hosts, anon_uid, anon_gid, auth_type, options): if exp_path is None: exp_path = "/nfs_exp_%s" % _random_vpd()[:8] self.sim_fs_of_id(sim_fs_id) try: self._data_add( 'exps', { 'fs_id': sim_fs_id, 'exp_path': exp_path, 'anon_uid': anon_uid, 'anon_gid': anon_gid, 'auth_type': auth_type, 'options': options, }) except sqlite3.IntegrityError as sql_error: # TODO(Gris Ge): Should we create new error instead of # NAME_CONFLICT? raise LsmError( ErrorNumber.NAME_CONFLICT, "Export path is already used by other NFS export") sim_exp_id = self.lastrowid for root_host in root_hosts: self._data_add( 'exp_root_hosts', { 'host': root_host, 'exp_id': sim_exp_id, }) for rw_host in rw_hosts: self._data_add( 'exp_rw_hosts', { 'host': rw_host, 'exp_id': sim_exp_id, }) for ro_host in ro_hosts: self._data_add( 'exp_ro_hosts', { 'host': ro_host, 'exp_id': sim_exp_id, }) return sim_exp_id def sim_exp_delete(self, sim_exp_id): self.sim_exp_of_id(sim_exp_id) self._data_delete('exps', 'id="%s"' % sim_exp_id) def sim_tgts(self): """ Return a list of sim_tgt dict. """ return self._get_table('tgts_view') def sim_bats(self): """ Return a list of sim_bat dict. """ return self._get_table('bats_view') def sim_vol_pdc_set(self, sim_vol_id, pdc): self.sim_vol_of_id(sim_vol_id) self._data_update('volumes', sim_vol_id, 'phy_disk_cache', pdc) def sim_vol_rcp_set(self, sim_vol_id, rcp): self.sim_vol_of_id(sim_vol_id) self._data_update('volumes', sim_vol_id, 'read_cache_policy', rcp) def sim_vol_wcp_set(self, sim_vol_id, wcp): self.sim_vol_of_id(sim_vol_id) self._data_update('volumes', sim_vol_id, 'write_cache_policy', wcp) class SimArray(object): SIM_DATA_FILE = os.getenv("LSM_SIM_DATA", tempfile.gettempdir() + '/lsm_sim_data') @staticmethod def _lsm_id_to_sim_id(lsm_id, lsm_error): try: return int(lsm_id[-BackStore._ID_FMT_LEN:]) except ValueError: raise lsm_error @staticmethod def _sim_job_id_of(job_id): return SimArray._lsm_id_to_sim_id( job_id, LsmError(ErrorNumber.NOT_FOUND_JOB, "Job not found")) @staticmethod def _sim_pool_id_of(pool_id): return SimArray._lsm_id_to_sim_id( pool_id, LsmError(ErrorNumber.NOT_FOUND_POOL, "Pool not found")) @staticmethod def _sim_vol_id_of(vol_id): return SimArray._lsm_id_to_sim_id( vol_id, LsmError( ErrorNumber.NOT_FOUND_VOLUME, "Volume not found")) @staticmethod def _sim_fs_id_of(fs_id): return SimArray._lsm_id_to_sim_id( fs_id, LsmError( ErrorNumber.NOT_FOUND_FS, "File system not found")) @staticmethod def _sim_fs_snap_id_of(snap_id): return SimArray._lsm_id_to_sim_id( snap_id, LsmError( ErrorNumber.NOT_FOUND_FS_SS, "File system snapshot not found")) @staticmethod def _sim_exp_id_of(exp_id): return SimArray._lsm_id_to_sim_id( exp_id, LsmError( ErrorNumber.NOT_FOUND_NFS_EXPORT, "File system export not found")) @staticmethod def _sim_ag_id_of(ag_id): return SimArray._lsm_id_to_sim_id( ag_id, LsmError( ErrorNumber.NOT_FOUND_NFS_EXPORT, "File system export not found")) @_handle_errors def __init__(self, statefile, timeout): if statefile is None: statefile = SimArray.SIM_DATA_FILE self.bs_obj = BackStore(statefile, timeout) self.bs_obj.check_version_and_init() self.statefile = statefile self.timeout = timeout def _job_create(self, data_type=None, sim_data_id=None): sim_job_id = self.bs_obj.sim_job_create( data_type, sim_data_id) return "JOB_ID_%0*d" % (BackStore._ID_FMT_LEN, sim_job_id) @_handle_errors def job_status(self, job_id, flags=0): sim_job_id = SimArray._sim_job_id_of(job_id) (progress, data_type, sim_data) = self.bs_obj.sim_job_status( sim_job_id) status = JobStatus.INPROGRESS if progress == 100: status = JobStatus.COMPLETE data = None if data_type == BackStore.JOB_DATA_TYPE_VOL: data = SimArray._sim_vol_2_lsm(sim_data) elif data_type == BackStore.JOB_DATA_TYPE_FS: data = SimArray._sim_fs_2_lsm(sim_data) elif data_type == BackStore.JOB_DATA_TYPE_FS_SNAP: data = SimArray._sim_fs_snap_2_lsm(sim_data) return (status, progress, data) @_handle_errors def job_free(self, job_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_job_delete(SimArray._sim_job_id_of(job_id)) self.bs_obj.trans_commit() return None @_handle_errors def time_out_set(self, ms, flags=0): self.bs_obj = BackStore(self.statefile, int(int_div(ms, 1000))) self.timeout = ms return None @_handle_errors def time_out_get(self, flags=0): return self.timeout @staticmethod def _sim_sys_2_lsm(sim_sys): return System( sim_sys['id'], sim_sys['name'], sim_sys['status'], sim_sys['status_info'], _fw_version=sim_sys["version"], _mode=BackStore.SYS_MODE, _read_cache_pct=sim_sys['read_cache_pct']) @_handle_errors def systems(self): return list( SimArray._sim_sys_2_lsm(sim_sys) for sim_sys in self.bs_obj.sim_syss()) @_handle_errors def system_read_cache_pct_update(self, system, read_pct, flags=0): if system.id != BackStore.SYS_ID: raise LsmError( ErrorNumber.NOT_FOUND_SYSTEM, "System not found") self.bs_obj.trans_begin() self.bs_obj._data_update("systems", BackStore.SYS_ID, "read_cache_pct", read_pct); self.bs_obj.trans_commit() return None @staticmethod def _sim_vol_2_lsm(sim_vol): return Volume(sim_vol['lsm_vol_id'], sim_vol['name'], sim_vol['vpd83'], BackStore.BLK_SIZE, int(int_div(sim_vol['total_space'], BackStore.BLK_SIZE)), sim_vol['admin_state'], BackStore.SYS_ID, sim_vol['lsm_pool_id']) @_handle_errors def volumes(self): return list( SimArray._sim_vol_2_lsm(v) for v in self.bs_obj.sim_vols()) @staticmethod def _sim_pool_2_lsm(sim_pool): pool_id = sim_pool['lsm_pool_id'] name = sim_pool['name'] total_space = sim_pool['total_space'] free_space = sim_pool['free_space'] status = sim_pool['status'] status_info = sim_pool['status_info'] sys_id = BackStore.SYS_ID element_type = sim_pool['element_type'] unsupported_actions = sim_pool['unsupported_actions'] return Pool( pool_id, name, element_type, unsupported_actions, total_space, free_space, status, status_info, sys_id) @_handle_errors def pools(self, flags=0): self.bs_obj.trans_begin() sim_pools = self.bs_obj.sim_pools() self.bs_obj.trans_rollback() return list( SimArray._sim_pool_2_lsm(sim_pool) for sim_pool in sim_pools) @staticmethod def _sim_disk_2_lsm(sim_disk): disk_status = Disk.STATUS_OK if sim_disk['role'] is None: disk_status |= Disk.STATUS_FREE return Disk( sim_disk['lsm_disk_id'], sim_disk['name'], sim_disk['disk_type'], BackStore.BLK_SIZE, int(int_div(sim_disk['total_space'], BackStore.BLK_SIZE)), disk_status, BackStore.SYS_ID, _vpd83=sim_disk['vpd83'], _location=sim_disk['location'], _rpm=sim_disk['rpm'], _link_type=sim_disk['link_type']) @_handle_errors def disks(self): return list( SimArray._sim_disk_2_lsm(sim_disk) for sim_disk in self.bs_obj.sim_disks()) @_handle_errors def volume_create(self, pool_id, vol_name, size_bytes, thinp, flags=0, _internal_use=False, _is_hw_raid_vol=0): """ The '_internal_use' parameter is only for SimArray internal use. This method will return the new sim_vol id instead of job_id when '_internal_use' marked as True. """ if _internal_use is False: self.bs_obj.trans_begin() new_sim_vol_id = self.bs_obj.sim_vol_create( vol_name, size_bytes, SimArray._sim_pool_id_of(pool_id), is_hw_raid_vol=_is_hw_raid_vol) if _internal_use: return new_sim_vol_id job_id = self._job_create( BackStore.JOB_DATA_TYPE_VOL, new_sim_vol_id) self.bs_obj.trans_commit() return job_id, None @_handle_errors def volume_delete(self, vol_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_vol_delete(SimArray._sim_vol_id_of(vol_id)) job_id = self._job_create() self.bs_obj.trans_commit() return job_id @_handle_errors def volume_resize(self, vol_id, new_size_bytes, flags=0): self.bs_obj.trans_begin() sim_vol_id = SimArray._sim_vol_id_of(vol_id) self.bs_obj.sim_vol_resize(sim_vol_id, new_size_bytes) job_id = self._job_create( BackStore.JOB_DATA_TYPE_VOL, sim_vol_id) self.bs_obj.trans_commit() return job_id, None @_handle_errors def volume_replicate(self, dst_pool_id, rep_type, src_vol_id, new_vol_name, flags=0): self.bs_obj.trans_begin() src_sim_vol_id = SimArray._sim_pool_id_of(src_vol_id) # Verify the existence of source volume src_sim_vol = self.bs_obj.sim_vol_of_id(src_sim_vol_id) dst_sim_vol_id = self.volume_create( dst_pool_id, new_vol_name, src_sim_vol['total_space'], Volume.PROVISION_FULL, _internal_use=True) self.bs_obj.sim_vol_replica(src_sim_vol_id, dst_sim_vol_id, rep_type) job_id = self._job_create( BackStore.JOB_DATA_TYPE_VOL, dst_sim_vol_id) self.bs_obj.trans_commit() return job_id, None @_handle_errors def volume_replicate_range_block_size(self, sys_id, flags=0): if sys_id != BackStore.SYS_ID: raise LsmError( ErrorNumber.NOT_FOUND_SYSTEM, "System not found") return BackStore.BLK_SIZE @_handle_errors def volume_replicate_range(self, rep_type, src_vol_id, dst_vol_id, ranges, flags=0): self.bs_obj.trans_begin() # TODO(Gris Ge): check whether star_blk + count is out of volume # boundary # TODO(Gris Ge): Should check block overlap. self.bs_obj.sim_vol_replica( SimArray._sim_pool_id_of(src_vol_id), SimArray._sim_pool_id_of(dst_vol_id), rep_type, ranges) job_id = self._job_create() self.bs_obj.trans_commit() return job_id @_handle_errors def volume_enable(self, vol_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_vol_state_change( SimArray._sim_vol_id_of(vol_id), Volume.ADMIN_STATE_ENABLED) self.bs_obj.trans_commit() return None @_handle_errors def volume_disable(self, vol_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_vol_state_change( SimArray._sim_vol_id_of(vol_id), Volume.ADMIN_STATE_DISABLED) self.bs_obj.trans_commit() return None @_handle_errors def volume_child_dependency(self, vol_id, flags=0): # TODO(Gris Ge): API defination is blur: # 0. Should we break replication if provided volume is a # replication target? # Assuming answer is no. # 1. _client.py comments incorrect: # "Implies that this volume cannot be deleted or possibly # modified because it would affect its children" # The 'modify' here is incorrect. If data on source volume # changes, SYNC_MIRROR replication will change all target # volumes. # 2. Should 'mask' relationship included? # # Assuming only replication counts here. # 3. For volume internal block replication, should we return # True or False. # # Assuming False # 4. volume_child_dependency_rm() against volume internal # block replication, remove replication or raise error? # # Assuming remove replication src_sim_vol_id = SimArray._sim_vol_id_of(vol_id) dst_sim_vol_ids = self.bs_obj.dst_sim_vol_ids_of_src(src_sim_vol_id) for dst_sim_fs_id in dst_sim_vol_ids: if dst_sim_fs_id != src_sim_vol_id: return True return False @_handle_errors def volume_child_dependency_rm(self, vol_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_vol_src_replica_break( SimArray._sim_vol_id_of(vol_id)) job_id = self._job_create() self.bs_obj.trans_commit() return job_id @staticmethod def _sim_fs_2_lsm(sim_fs): return FileSystem(sim_fs['lsm_fs_id'], sim_fs['name'], sim_fs['total_space'], sim_fs['free_space'], sim_fs['lsm_pool_id'], BackStore.SYS_ID) @_handle_errors def fs(self): return list(SimArray._sim_fs_2_lsm(f) for f in self.bs_obj.sim_fss()) @_handle_errors def fs_create(self, pool_id, fs_name, size_bytes, flags=0, _internal_use=False): if not _internal_use: self.bs_obj.trans_begin() new_sim_fs_id = self.bs_obj.sim_fs_create( fs_name, size_bytes, SimArray._sim_pool_id_of(pool_id)) if _internal_use: return new_sim_fs_id job_id = self._job_create( BackStore.JOB_DATA_TYPE_FS, new_sim_fs_id) self.bs_obj.trans_commit() return job_id, None @_handle_errors def fs_delete(self, fs_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_fs_delete(SimArray._sim_fs_id_of(fs_id)) job_id = self._job_create() self.bs_obj.trans_commit() return job_id @_handle_errors def fs_resize(self, fs_id, new_size_bytes, flags=0): sim_fs_id = SimArray._sim_fs_id_of(fs_id) self.bs_obj.trans_begin() self.bs_obj.sim_fs_resize(sim_fs_id, new_size_bytes) job_id = self._job_create(BackStore.JOB_DATA_TYPE_FS, sim_fs_id) self.bs_obj.trans_commit() return job_id, None @_handle_errors def fs_clone(self, src_fs_id, dst_fs_name, snap_id, flags=0): self.bs_obj.trans_begin() sim_fs_snap_id = None if snap_id: sim_fs_snap_id = SimArray._sim_fs_snap_id_of(snap_id) src_sim_fs_id = SimArray._sim_fs_id_of(src_fs_id) src_sim_fs = self.bs_obj.sim_fs_of_id(src_sim_fs_id) pool_id = src_sim_fs['lsm_pool_id'] dst_sim_fs_id = self.fs_create( pool_id, dst_fs_name, src_sim_fs['total_space'], _internal_use=True) self.bs_obj.sim_fs_clone(src_sim_fs_id, dst_sim_fs_id, sim_fs_snap_id) job_id = self._job_create( BackStore.JOB_DATA_TYPE_FS, dst_sim_fs_id) self.bs_obj.trans_commit() return job_id, None @_handle_errors def fs_file_clone(self, fs_id, src_fs_name, dst_fs_name, snap_id, flags=0): self.bs_obj.trans_begin() sim_fs_snap_id = None if snap_id: sim_fs_snap_id = SimArray._sim_fs_snap_id_of(snap_id) self.bs_obj.sim_fs_file_clone( SimArray._sim_fs_id_of(fs_id), src_fs_name, dst_fs_name, sim_fs_snap_id) job_id = self._job_create() self.bs_obj.trans_commit() return job_id @staticmethod def _sim_fs_snap_2_lsm(sim_fs_snap): return FsSnapshot(sim_fs_snap['lsm_fs_snap_id'], sim_fs_snap['name'], sim_fs_snap['timestamp']) @_handle_errors def fs_snapshots(self, fs_id, flags=0): return list( SimArray._sim_fs_snap_2_lsm(s) for s in self.bs_obj.sim_fs_snaps( SimArray._sim_fs_id_of(fs_id))) @_handle_errors def fs_snapshot_create(self, fs_id, snap_name, flags=0): self.bs_obj.trans_begin() sim_fs_snap_id = self.bs_obj.sim_fs_snap_create( SimArray._sim_fs_id_of(fs_id), snap_name) job_id = self._job_create( BackStore.JOB_DATA_TYPE_FS_SNAP, sim_fs_snap_id) self.bs_obj.trans_commit() return job_id, None @_handle_errors def fs_snapshot_delete(self, fs_id, snap_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_fs_snap_delete( SimArray._sim_fs_snap_id_of(snap_id), SimArray._sim_fs_id_of(fs_id)) job_id = self._job_create() self.bs_obj.trans_commit() return job_id @_handle_errors def fs_snapshot_restore(self, fs_id, snap_id, files, restore_files, flag_all_files, flags): self.bs_obj.trans_begin() sim_fs_snap_id = None if snap_id: sim_fs_snap_id = SimArray._sim_fs_snap_id_of(snap_id) self.bs_obj.sim_fs_snap_restore( SimArray._sim_fs_id_of(fs_id), sim_fs_snap_id, files, restore_files, flag_all_files) job_id = self._job_create() self.bs_obj.trans_commit() return job_id @_handle_errors def fs_child_dependency(self, fs_id, files, flags=0, _internal_use=False): sim_fs_id = SimArray._sim_fs_id_of(fs_id) if _internal_use is False: self.bs_obj.trans_begin() if self.bs_obj.clone_dst_sim_fs_ids_of_src(sim_fs_id) == [] and \ self.bs_obj.sim_fs_snaps(sim_fs_id) == []: if _internal_use is False: self.bs_obj.trans_rollback() return False if _internal_use is False: self.bs_obj.trans_rollback() return True @_handle_errors def fs_child_dependency_rm(self, fs_id, files, flags=0): """ Assuming API defination is break all clone relationship and remove all snapshot of this source file system. """ self.bs_obj.trans_begin() if self.fs_child_dependency(fs_id, files, _internal_use=True) is False: raise LsmError( ErrorNumber.NO_STATE_CHANGE, "No snapshot or fs clone target found for this file system") src_sim_fs_id = SimArray._sim_fs_id_of(fs_id) self.bs_obj.sim_fs_src_clone_break(src_sim_fs_id) self.bs_obj.sim_fs_snap_del_by_fs(src_sim_fs_id) job_id = self._job_create() self.bs_obj.trans_commit() return job_id @staticmethod def _sim_exp_2_lsm(sim_exp): return NfsExport(sim_exp['lsm_exp_id'], sim_exp['lsm_fs_id'], sim_exp['exp_path'], sim_exp['auth_type'], sim_exp['root_hosts'], sim_exp['rw_hosts'], sim_exp['ro_hosts'], sim_exp['anon_uid'], sim_exp['anon_gid'], sim_exp['options']) @_handle_errors def exports(self, flags=0): return [SimArray._sim_exp_2_lsm(e) for e in self.bs_obj.sim_exps()] @_handle_errors def fs_export(self, fs_id, exp_path, root_hosts, rw_hosts, ro_hosts, anon_uid, anon_gid, auth_type, options, flags=0): self.bs_obj.trans_begin() sim_exp_id = self.bs_obj.sim_exp_create( SimArray._sim_fs_id_of(fs_id), exp_path, root_hosts, rw_hosts, ro_hosts, anon_uid, anon_gid, auth_type, options) sim_exp = self.bs_obj.sim_exp_of_id(sim_exp_id) self.bs_obj.trans_commit() return SimArray._sim_exp_2_lsm(sim_exp) @_handle_errors def fs_unexport(self, exp_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_exp_delete(SimArray._sim_exp_id_of(exp_id)) self.bs_obj.trans_commit() return None @staticmethod def _sim_ag_2_lsm(sim_ag): return AccessGroup(sim_ag['lsm_ag_id'], sim_ag['name'], sim_ag['init_ids'], sim_ag['init_type'], BackStore.SYS_ID) @_handle_errors def ags(self): return list(SimArray._sim_ag_2_lsm(a) for a in self.bs_obj.sim_ags()) @_handle_errors def access_group_create(self, name, init_id, init_type, sys_id, flags=0): if sys_id != BackStore.SYS_ID: raise LsmError( ErrorNumber.NOT_FOUND_SYSTEM, "System not found") self.bs_obj.trans_begin() new_sim_ag_id = self.bs_obj.sim_ag_create(name, init_type, init_id) new_sim_ag = self.bs_obj.sim_ag_of_id(new_sim_ag_id) self.bs_obj.trans_commit() return SimArray._sim_ag_2_lsm(new_sim_ag) @_handle_errors def access_group_delete(self, ag_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_ag_delete(SimArray._sim_ag_id_of(ag_id)) self.bs_obj.trans_commit() return None @_handle_errors def access_group_initiator_add(self, ag_id, init_id, init_type, flags=0): sim_ag_id = SimArray._sim_ag_id_of(ag_id) self.bs_obj.trans_begin() self.bs_obj.sim_ag_init_add(sim_ag_id, init_id, init_type) new_sim_ag = self.bs_obj.sim_ag_of_id(sim_ag_id) self.bs_obj.trans_commit() return SimArray._sim_ag_2_lsm(new_sim_ag) @_handle_errors def access_group_initiator_delete(self, ag_id, init_id, init_type, flags=0): sim_ag_id = SimArray._sim_ag_id_of(ag_id) self.bs_obj.trans_begin() self.bs_obj.sim_ag_init_delete(sim_ag_id, init_id) sim_ag = self.bs_obj.sim_ag_of_id(sim_ag_id) self.bs_obj.trans_commit() return SimArray._sim_ag_2_lsm(sim_ag) @_handle_errors def volume_mask(self, ag_id, vol_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_vol_mask( SimArray._sim_vol_id_of(vol_id), SimArray._sim_ag_id_of(ag_id)) self.bs_obj.trans_commit() return None @_handle_errors def volume_unmask(self, ag_id, vol_id, flags=0): self.bs_obj.trans_begin() self.bs_obj.sim_vol_unmask( SimArray._sim_vol_id_of(vol_id), SimArray._sim_ag_id_of(ag_id)) self.bs_obj.trans_commit() return None @_handle_errors def volumes_accessible_by_access_group(self, ag_id, flags=0): self.bs_obj.trans_begin() sim_vols = self.bs_obj.sim_vols( sim_ag_id=SimArray._sim_ag_id_of(ag_id)) self.bs_obj.trans_rollback() return [SimArray._sim_vol_2_lsm(v) for v in sim_vols] @_handle_errors def access_groups_granted_to_volume(self, vol_id, flags=0): self.bs_obj.trans_begin() sim_ags = self.bs_obj.sim_ags( sim_vol_id=SimArray._sim_vol_id_of(vol_id)) self.bs_obj.trans_rollback() return [SimArray._sim_ag_2_lsm(a) for a in sim_ags] @_handle_errors def iscsi_chap_auth(self, init_id, in_user, in_pass, out_user, out_pass, flags=0): self.bs_obj.trans_begin() self.bs_obj.iscsi_chap_auth_set( init_id, in_user, in_pass, out_user, out_pass) self.bs_obj.trans_commit() return None @staticmethod def _sim_tgt_2_lsm(sim_tgt): return TargetPort( sim_tgt['lsm_tgt_id'], sim_tgt['port_type'], sim_tgt['service_address'], sim_tgt['network_address'], sim_tgt['physical_address'], sim_tgt['physical_name'], BackStore.SYS_ID) @_handle_errors def target_ports(self): return list(SimArray._sim_tgt_2_lsm(t) for t in self.bs_obj.sim_tgts()) @_handle_errors def volume_raid_info(self, lsm_vol): sim_pool = self.bs_obj.sim_pool_of_id( SimArray._lsm_id_to_sim_id( lsm_vol.pool_id, LsmError(ErrorNumber.NOT_FOUND_POOL, "Pool not found"))) min_io_size = BackStore.BLK_SIZE opt_io_size = Volume.OPT_IO_SIZE_UNKNOWN if sim_pool['member_type'] == Pool.MEMBER_TYPE_POOL: sim_pool = self.bs_obj.sim_pool_of_id(sim_pool['parent_pool_id']) raid_type = sim_pool['raid_type'] disk_count = sim_pool['disk_count'] strip_size = sim_pool['strip_size'] min_io_size = strip_size if raid_type == Volume.RAID_TYPE_UNKNOWN or \ raid_type == Volume.RAID_TYPE_OTHER: return [ raid_type, strip_size, disk_count, min_io_size, opt_io_size] if raid_type == Volume.RAID_TYPE_MIXED: raise LsmError( ErrorNumber.PLUGIN_BUG, "volume_raid_info(): Got unsupported RAID_TYPE_MIXED pool " "%s" % sim_pool['lsm_pool_id']) if raid_type == Volume.RAID_TYPE_RAID1 or \ raid_type == Volume.RAID_TYPE_JBOD: opt_io_size = BackStore.BLK_SIZE else: opt_io_size = int(sim_pool['data_disk_count'] * strip_size) return [raid_type, strip_size, disk_count, min_io_size, opt_io_size] @_handle_errors def pool_member_info(self, lsm_pool): sim_pool = self.bs_obj.sim_pool_of_id( SimArray._lsm_id_to_sim_id( lsm_pool.id, LsmError(ErrorNumber.NOT_FOUND_POOL, "Pool not found"))) member_type = sim_pool['member_type'] member_ids = [] if member_type == Pool.MEMBER_TYPE_POOL: member_ids = [sim_pool['parent_lsm_pool_id']] elif member_type == Pool.MEMBER_TYPE_DISK: member_ids = self.bs_obj.lsm_disk_ids_of_pool(sim_pool['id']) else: member_type = Pool.MEMBER_TYPE_UNKNOWN return sim_pool['raid_type'], member_type, member_ids @_handle_errors def volume_raid_create_cap_get(self, system): if system.id != BackStore.SYS_ID: raise LsmError( ErrorNumber.NOT_FOUND_SYSTEM, "System not found") return ( BackStore.SUPPORTED_VCR_RAID_TYPES, BackStore.SUPPORTED_VCR_STRIP_SIZES) @_handle_errors def volume_raid_create(self, name, raid_type, disks, strip_size): if raid_type not in BackStore.SUPPORTED_VCR_RAID_TYPES: raise LsmError( ErrorNumber.NO_SUPPORT, "Provided 'raid_type' is not supported") if strip_size == Volume.VCR_STRIP_SIZE_DEFAULT: strip_size = BackStore.DEFAULT_STRIP_SIZE elif strip_size not in BackStore.SUPPORTED_VCR_STRIP_SIZES: raise LsmError( ErrorNumber.NO_SUPPORT, "Provided 'strip_size' is not supported") self.bs_obj.trans_begin() pool_name = "Pool for volume %s" % name sim_disk_ids = [ SimArray._lsm_id_to_sim_id( d.id, LsmError(ErrorNumber.NOT_FOUND_DISK, "Disk not found")) for d in disks] for disk in disks: if not disk.status & Disk.STATUS_FREE: raise LsmError( ErrorNumber.DISK_NOT_FREE, "Disk %s is not in DISK.STATUS_FREE mode" % disk.id) try: sim_pool_id = self.bs_obj.sim_pool_create_from_disk( name=pool_name, raid_type=raid_type, sim_disk_ids=sim_disk_ids, element_type=Pool.ELEMENT_TYPE_VOLUME, unsupported_actions=Pool.UNSUPPORTED_VOLUME_GROW | Pool.UNSUPPORTED_VOLUME_SHRINK, strip_size=strip_size) except sqlite3.IntegrityError as sql_error: raise LsmError( ErrorNumber.NAME_CONFLICT, "Name '%s' is already in use by other volume" % name) sim_pool = self.bs_obj.sim_pool_of_id(sim_pool_id) sim_vol_id = self.volume_create( # TODO Figure out why sim_pool freespace ends up being smaller when # we call _check_pool_free_space in volume_create internals sim_pool['lsm_pool_id'], name, sim_pool['free_space'] - 1024, Volume.PROVISION_FULL, _internal_use=True, _is_hw_raid_vol=1) sim_vol = self.bs_obj.sim_vol_of_id(sim_vol_id) self.bs_obj.trans_commit() return SimArray._sim_vol_2_lsm(sim_vol) @_handle_errors def volume_ident_led_on(self, volume, flags=0): sim_volume_id = SimArray._lsm_id_to_sim_id( volume.id, LsmError( ErrorNumber.NOT_FOUND_VOLUME, "Volume not found")) sim_vol = self.bs_obj.sim_vol_of_id(sim_volume_id) return None @_handle_errors def volume_ident_led_off(self, volume, flags=0): sim_volume_id = SimArray._lsm_id_to_sim_id( volume.id, LsmError( ErrorNumber.NOT_FOUND_VOLUME, "Volume not found")) sim_vol = self.bs_obj.sim_vol_of_id(sim_volume_id) return None @staticmethod def _sim_bat_2_lsm(sim_bat): return Battery(sim_bat['lsm_bat_id'], sim_bat['name'], sim_bat['type'], sim_bat['status'], BackStore.SYS_ID) @_handle_errors def batteries(self): return list(SimArray._sim_bat_2_lsm(t) for t in self.bs_obj.sim_bats()) @_handle_errors def volume_cache_info(self, lsm_vol): sim_vol = self.bs_obj.sim_vol_of_id(SimArray._lsm_id_to_sim_id( lsm_vol.id, LsmError(ErrorNumber.NOT_FOUND_VOLUME, "Volume not found"))) write_cache_status = Volume.WRITE_CACHE_STATUS_WRITE_THROUGH read_cache_status = Volume.READ_CACHE_STATUS_DISABLED flag_battery_ok = False for sim_bat in self.bs_obj.sim_bats(): if sim_bat['status'] == Battery.STATUS_OK: flag_battery_ok = True # Assuming system always has functional RAM if sim_vol['write_cache_policy'] == Volume.WRITE_CACHE_POLICY_AUTO: if flag_battery_ok: write_cache_status = Volume.WRITE_CACHE_STATUS_WRITE_BACK elif (sim_vol['write_cache_policy'] == Volume.WRITE_CACHE_POLICY_WRITE_BACK): write_cache_status = Volume.WRITE_CACHE_STATUS_WRITE_BACK elif (sim_vol['write_cache_policy'] == Volume.WRITE_CACHE_POLICY_UNKNOWN): write_cache_status = Volume.WRITE_CACHE_STATUS_UNKNOWN if sim_vol['read_cache_policy'] == Volume.READ_CACHE_POLICY_ENABLED: read_cache_status = Volume.READ_CACHE_STATUS_ENABLED elif sim_vol['read_cache_policy'] == Volume.READ_CACHE_POLICY_UNKNOWN: read_cache_status = Volume.READ_CACHE_STATUS_UNKNOWN return [sim_vol['write_cache_policy'], write_cache_status, sim_vol['read_cache_policy'], read_cache_status, sim_vol['phy_disk_cache']] @_handle_errors def volume_physical_disk_cache_update(self, volume, pdc, flags=0): self.bs_obj.trans_begin() sim_vol_id = SimArray._lsm_id_to_sim_id( volume.id, LsmError(ErrorNumber.NOT_FOUND_VOLUME, "Volume not found")) self.bs_obj.sim_vol_pdc_set(sim_vol_id, pdc) self.bs_obj.trans_commit() @_handle_errors def volume_write_cache_policy_update(self, volume, wcp, flags=0): self.bs_obj.trans_begin() sim_vol_id = SimArray._lsm_id_to_sim_id( volume.id, LsmError(ErrorNumber.NOT_FOUND_VOLUME, "Volume not found")) self.bs_obj.sim_vol_wcp_set(sim_vol_id, wcp) self.bs_obj.trans_commit() @_handle_errors def volume_read_cache_policy_update(self, volume, rcp, flags=0): self.bs_obj.trans_begin() sim_vol_id = SimArray._lsm_id_to_sim_id( volume.id, LsmError(ErrorNumber.NOT_FOUND_VOLUME, "Volume not found")) self.bs_obj.sim_vol_rcp_set(sim_vol_id, rcp) self.bs_obj.trans_commit() plugin/sim/simarray.pyc000064400000263521147576505410011225 0ustar00 .P`c@sddlZddlZddlZddlZddlZddlmZddlmZmZm Z m Z m Z m Z m Z mZmZmZmZmZmZmZmZdZdZdZdefdYZd efd YZd efd YZdS( iN(tsize_human_2_size_bytes(tSystemtVolumetDisktPoolt FileSystemt AccessGroupt FsSnapshott NfsExporttmd5tLsmErrort TargetPortt ErrorNumbert JobStatustBatterytint_divcsfd}|S(Ncsiy||SWnQtjk r}t|dtkrct|ddrc|djjnt|dkrtt j dntt j dt|ntk rt|dtkrt|ddr|djjnnlt k rd}t|dtkrEt|ddrE|djjntt j dt|nXdS(Nitbs_objsdatabase is lockeds%Timeout to require lock on state files%Got unexpected error from sqlite3: %ssGot unexpected error: %s( tsqlite3tOperationalErrorttypetSimArraythasattrRttrans_rollbacktstrR R tTIMEOUTt PLUGIN_BUGt Exception(targstkargst sql_errort base_error(tmethod(s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytwrapper s,)  ))((RR ((Rs;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_handle_errorsscCsSdg}x:tddD])}|jtdtjddqWdj|S(s. Generate a random VPD83 NAA_Type3 ID t50iis%02xit(trangetappendRtrandomtrandinttjoin(tvpdt_((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _random_vpd:s 'cCs<i}x/t|jD]\}}||||dMscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6NscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6OscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6PscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6QscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6RscCs |dkS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6SscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6TscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6UscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6VscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6WscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6XscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6YscCs|dko|ddkS(Niii((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6ZscCs|S(N((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6^scCs|S(N((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6_scCsdS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6`scCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6ascCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6bscCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6cscCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6dscCs t|dS(Ni(R(R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6escCst|ddS(Nii(R(R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6fscCst|ddS(Ni(R(R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6gscCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6hscCs|dS(Ni((R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6iscCst|ddS(Nii(R(R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6jscCst|ddS(Ni(R(R5((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR6kscCs}|ttjjkr4ttjd|ntj||tkrlttjd||fntj||S(s Return a integer indicating how many disks should be used as real data(not mirrored or parity) disks. Treating RAID 5 and 6 using fixed parity disk. s0data_disk_count(): Got unsupported raid type(%d)s;data_disk_count(): Illegal disk count(%d) for raid type(%d)( tlistR4t_RAID_DISK_CHKtkeysR R RtFalset_RAID_PARITY_DISK_COUNT_FUNC(t raid_typet disk_count((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytdata_disk_countns (t__name__t __module__RtRAID_TYPE_JBODtRAID_TYPE_RAID0tRAID_TYPE_RAID1tRAID_TYPE_RAID3tRAID_TYPE_RAID4tRAID_TYPE_RAID5tRAID_TYPE_RAID6tRAID_TYPE_RAID10tRAID_TYPE_RAID15tRAID_TYPE_RAID16tRAID_TYPE_RAID50tRAID_TYPE_RAID60tRAID_TYPE_RAID51tRAID_TYPE_RAID61R8R;t staticmethodR>(((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR4Ks>                          t BackStorec BseZdZdeeefZdZdZdZdZdZ dZ dZ dd Z e jZejZejZejZd Zd Zd Zejejejejejejej gZ!d d dd dd dd dd dd dd d d gZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+e,dZ-dZ.dZ/e0e0dZ1dZ2d Z3d!Z4d"Z5d#Z6d$Z7d%Z8d&d&d'Z9d&d(Z:d)Z;e0d*Z<e0d+Z=d,Z>d-Z?d.Z@eAd/ZBd&d0ZCd1ZDd2ZEd3ZFd4ZGd5ZHd6ZId7ZJe0d8ZKd9ZLd:ZMeAd;ZNe0d<ZOd=ZPd>ZQd?ZRd@ZSdAZTdBZUdCZVdDZWeXdEZYdFZZdGZ[dHZ\dIZ]e0dJZ^dKZ_dLZ`dMZadNZbdOZcdPZddQZedRZfdSZgdTZhdUZidVZjdWZkdXZldYZmdZZnd[Zod\ZpRS(]s4.1sLSM_SIMULATOR_DATA_%s_%siiissim-01sLSM simulated storage plug-iniiii t#iiii i@icCstjj|sHtjtj|tjtjBtj|dn||_d|_ t j |dt t|ddd|_t|j_d}|d7}|d7}|d 7}|d 7}|d 7}|d 7}|d 7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d7}|d 7}|d!7}|d"7}|d#7}|jid$tjd%6tjd&6tjd'6tjd(6tjd)6}|jj}y|j|Wn_t jk rS}d*t|krJq|n/t jk r}ttj d+|jnXdS(,Nittimeoutitisolation_levelt IMMEDIATEsPRAGMA foreign_keys = ON; s CREATE TABLE systems ( id TEXT PRIMARY KEY, name TEXT NOT NULL, status INTEGER NOT NULL, status_info TEXT, read_cache_pct INTEGER, version TEXT NOT NULL); s% CREATE TABLE tgts ( id INTEGER PRIMARY KEY, port_type INTEGER NOT NULL, service_address TEXT NOT NULL, network_address TEXT NOT NULL, physical_address TEXT NOT NULL, physical_name TEXT NOT NULL); s CREATE TABLE pools ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, status INTEGER NOT NULL, status_info TEXT, element_type INTEGER NOT NULL, unsupported_actions INTEGER, raid_type INTEGER NOT NULL, parent_pool_id INTEGER, member_type INTEGER, strip_size INTEGER, total_space LONG); s CREATE TABLE disks ( id INTEGER PRIMARY KEY, total_space LONG NOT NULL, disk_type INTEGER NOT NULL, status INTEGER NOT NULL, disk_prefix TEXT NOT NULL, location TEXT NOT NULL, owner_pool_id INTEGER, role TEXT, vpd83 TEXT, rpm INTEGER, link_type INTEGER, FOREIGN KEY(owner_pool_id) REFERENCES pools(id) ON DELETE SET DEFAULT); s; CREATE TABLE volumes ( id INTEGER PRIMARY KEY, vpd83 TEXT NOT NULL, name TEXT UNIQUE NOT NULL, total_space LONG NOT NULL, consumed_size LONG NOT NULL, admin_state INTEGER, is_hw_raid_vol INTEGER, write_cache_policy INTEGER NOT NULL, read_cache_policy INTEGER NOT NULL, phy_disk_cache INTEGER NOT NULL, pool_id INTEGER NOT NULL, FOREIGN KEY(pool_id) REFERENCES pools(id) ON DELETE CASCADE); sx CREATE TABLE ags ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL); s CREATE TABLE inits ( id TEXT UNIQUE NOT NULL, init_type INTEGER NOT NULL, owner_ag_id INTEGER NOT NULL, FOREIGN KEY(owner_ag_id) REFERENCES ags(id) ON DELETE CASCADE); s  CREATE TABLE vol_masks ( vol_id INTEGER NOT NULL, ag_id INTEGER NOT NULL, FOREIGN KEY(vol_id) REFERENCES volumes(id) ON DELETE CASCADE, FOREIGN KEY(ag_id) REFERENCES ags(id) ON DELETE CASCADE); sV CREATE TABLE vol_reps ( rep_type INTEGER, src_vol_id INTEGER NOT NULL, dst_vol_id INTEGER NOT NULL, FOREIGN KEY(src_vol_id) REFERENCES volumes(id) ON DELETE CASCADE, FOREIGN KEY(dst_vol_id) REFERENCES volumes(id) ON DELETE CASCADE); s` CREATE TABLE fss ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, total_space LONG NOT NULL, consumed_size LONG NOT NULL, free_space LONG, pool_id INTEGER NOT NULL, FOREIGN KEY(pool_id) REFERENCES pools(id) ON DELETE CASCADE); s CREATE TABLE fs_snaps ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, fs_id INTEGER NOT NULL, timestamp LONG NOT NULL, FOREIGN KEY(fs_id) REFERENCES fss(id) ON DELETE CASCADE); s- CREATE TABLE fs_clones ( src_fs_id INTEGER NOT NULL, dst_fs_id INTEGER NOT NULL, FOREIGN KEY(src_fs_id) REFERENCES fss(id) ON DELETE CASCADE, FOREIGN KEY(dst_fs_id) REFERENCES fss(id) ON DELETE CASCADE); sd CREATE TABLE exps ( id INTEGER PRIMARY KEY, fs_id INTEGER NOT NULL, exp_path TEXT UNIQUE NOT NULL, auth_type TEXT, anon_uid INTEGER, anon_gid INTEGER, options TEXT, FOREIGN KEY(fs_id) REFERENCES fss(id) ON DELETE CASCADE); s CREATE TABLE exp_root_hosts ( host TEXT NOT NULL, exp_id INTEGER NOT NULL, FOREIGN KEY(exp_id) REFERENCES exps(id) ON DELETE CASCADE); s CREATE TABLE exp_rw_hosts ( host TEXT NOT NULL, exp_id INTEGER NOT NULL, FOREIGN KEY(exp_id) REFERENCES exps(id) ON DELETE CASCADE); s CREATE TABLE exp_ro_hosts ( host TEXT NOT NULL, exp_id INTEGER NOT NULL, FOREIGN KEY(exp_id) REFERENCES exps(id) ON DELETE CASCADE); s CREATE TABLE jobs ( id INTEGER PRIMARY KEY, duration REAL NOT NULL, timestamp TEXT NOT NULL, data_type INTEGER, data_id INTEGER); s CREATE TABLE batteries ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, type INTEGER NOT NULL, status INTEGER NOT NULL); s CREATE VIEW pools_view AS SELECT pool0.id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool0.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id, pool0.name, pool0.status, pool0.status_info, pool0.element_type, pool0.unsupported_actions, pool0.raid_type, pool0.member_type, pool0.parent_pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool0.parent_pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) parent_lsm_pool_id, pool0.strip_size, pool1.total_space total_space, pool1.total_space - pool2.vol_consumed_size - pool3.fs_consumed_size - pool4.sub_pool_consumed_size free_space, pool1.data_disk_count, pool5.disk_count FROM pools pool0 LEFT JOIN ( SELECT pool.id, ifnull(pool.total_space, ifnull(SUM(disk.total_space), 0)) total_space, COUNT(disk.id) data_disk_count FROM pools pool LEFT JOIN disks disk ON pool.id = disk.owner_pool_id AND disk.role = 'DATA' GROUP BY pool.id ) pool1 ON pool0.id = pool1.id LEFT JOIN ( SELECT pool.id, ifnull(SUM(volume.consumed_size), 0) vol_consumed_size FROM pools pool LEFT JOIN volumes volume ON volume.pool_id = pool.id GROUP BY pool.id ) pool2 ON pool0.id = pool2.id LEFT JOIN ( SELECT pool.id, ifnull(SUM(fs.consumed_size), 0) fs_consumed_size FROM pools pool LEFT JOIN fss fs ON fs.pool_id = pool.id GROUP BY pool.id ) pool3 ON pool0.id = pool3.id LEFT JOIN ( SELECT pool.id, ifnull(SUM(sub_pool.total_space), 0) sub_pool_consumed_size FROM pools pool LEFT JOIN pools sub_pool ON sub_pool.parent_pool_id = pool.id GROUP BY pool.id ) pool4 ON pool0.id = pool4.id LEFT JOIN ( SELECT pool.id, COUNT(disk.id) disk_count FROM pools pool LEFT JOIN disks disk ON pool.id = disk.owner_pool_id GROUP BY pool.id ) pool5 ON pool0.id = pool5.id GROUP BY pool0.id; s CREATE VIEW tgts_view AS SELECT id, 'TGT_PORT_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_tgt_id, port_type, service_address, network_address, physical_address, physical_name FROM tgts; s CREATE VIEW disks_view AS SELECT id, 'DISK_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_disk_id, disk_prefix || '_' || id name, total_space, disk_type, role, status, vpd83, rpm, link_type, location, owner_pool_id FROM disks; sf CREATE VIEW volumes_view AS SELECT id, 'VOL_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_vol_id, vpd83, name, total_space, consumed_size, admin_state, is_hw_raid_vol, write_cache_policy, read_cache_policy, phy_disk_cache, pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id FROM volumes; s CREATE VIEW fss_view AS SELECT id, 'FS_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_id, name, total_space, consumed_size, free_space, pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id FROM fss; s CREATE VIEW bats_view AS SELECT id, 'BAT_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_bat_id, name, type, status FROM batteries; sp CREATE VIEW fs_snaps_view AS SELECT id, 'FS_SNAP_ID_' || SUBSTR('{ID_PADDING}' || id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_snap_id, name, timestamp, fs_id, 'FS_ID_' || SUBSTR('{ID_PADDING}' || fs_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_id FROM fs_snaps; s; CREATE VIEW volumes_by_ag_view AS SELECT vol.id, 'VOL_ID_' || SUBSTR('{ID_PADDING}' || vol.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_vol_id, vol.vpd83, vol.name, vol.total_space, vol.consumed_size, vol.pool_id, 'POOL_ID_' || SUBSTR('{ID_PADDING}' || vol.pool_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_pool_id, vol.admin_state, vol.is_hw_raid_vol, vol_mask.ag_id ag_id, vol.write_cache_policy, vol.read_cache_policy, vol.phy_disk_cache FROM volumes vol LEFT JOIN vol_masks vol_mask ON vol_mask.vol_id = vol.id; s CREATE VIEW ags_view AS SELECT ag.id, 'AG_ID_' || SUBSTR('{ID_PADDING}' || ag.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_ag_id, ag.name, CASE WHEN count(DISTINCT init.init_type) = 1 THEN init.init_type WHEN count(DISTINCT init.init_type) = 2 THEN {AG_INIT_TYPE_MIXED} ELSE {AG_INIT_TYPE_UNKNOWN} END init_type, group_concat(init.id, '{SPLITTER}') init_ids_str FROM ags ag LEFT JOIN inits init ON ag.id = init.owner_ag_id GROUP BY ag.id ORDER BY init.init_type; sO CREATE VIEW ags_by_vol_view AS SELECT ag_new.id, 'AG_ID_' || SUBSTR('{ID_PADDING}' || ag_new.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_ag_id, ag_new.name, ag_new.init_type, ag_new.init_ids_str, vol_mask.vol_id vol_id FROM ( SELECT ag.id, ag.name, CASE WHEN count(DISTINCT init.init_type) = 1 THEN init.init_type WHEN count(DISTINCT init.init_type) = 2 THEN {AG_INIT_TYPE_MIXED} ELSE {AG_INIT_TYPE_UNKNOWN} END init_type, group_concat(init.id, '{SPLITTER}') init_ids_str FROM ags ag LEFT JOIN inits init ON ag.id = init.owner_ag_id GROUP BY ag.id ORDER BY init.init_type ) ag_new LEFT JOIN vol_masks vol_mask ON vol_mask.ag_id = ag_new.id ; sg CREATE VIEW exps_view AS SELECT exp.id, 'EXP_ID_' || SUBSTR('{ID_PADDING}' || exp.id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_exp_id, exp.fs_id, 'FS_ID_' || SUBSTR('{ID_PADDING}' || exp.fs_id, -{ID_FMT_LEN}, {ID_FMT_LEN}) lsm_fs_id, exp.exp_path, exp.auth_type, exp.anon_uid, exp.anon_gid, exp.options, exp2.exp_root_hosts_str, exp3.exp_rw_hosts_str, exp4.exp_ro_hosts_str FROM exps exp LEFT JOIN ( SELECT exp_t2.id, group_concat( exp_root_host.host, '{SPLITTER}') exp_root_hosts_str FROM exps exp_t2 LEFT JOIN exp_root_hosts exp_root_host ON exp_t2.id = exp_root_host.exp_id GROUP BY exp_t2.id ) exp2 ON exp.id = exp2.id LEFT JOIN ( SELECT exp_t3.id, group_concat( exp_rw_host.host, '{SPLITTER}') exp_rw_hosts_str FROM exps exp_t3 LEFT JOIN exp_rw_hosts exp_rw_host ON exp_t3.id = exp_rw_host.exp_id GROUP BY exp_t3.id ) exp3 ON exp.id = exp3.id LEFT JOIN ( SELECT exp_t4.id, group_concat( exp_ro_host.host, '{SPLITTER}') exp_ro_hosts_str FROM exps exp_t4 LEFT JOIN exp_ro_hosts exp_ro_host ON exp_t4.id = exp_ro_host.exp_id GROUP BY exp_t4.id ) exp4 ON exp.id = exp4.id GROUP BY exp.id; ; t0t ID_PADDINGt ID_FMT_LENtAG_INIT_TYPE_MIXEDtAG_INIT_TYPE_UNKNOWNtSPLITTERsalready existssLStored simulator state incompatible with simulator, please move or delete %s(!tostpathtexiststclosetopentO_WRONLYtO_CREATtchmodt statefiletNonet lastrowidRtconnecttintRtsql_connR3t row_factorytformatRPt _ID_FMT_LENRtINIT_TYPE_ISCSI_WWPN_MIXEDtINIT_TYPE_UNKNOWNt_LIST_SPLITTERR.t executescriptRRt DatabaseErrorR R tINVALID_ARGUMENT(tselfRcRRtsql_cmdtsql_curR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt__init__s#  '        ]'E     cCs{|j}t|dks)|d r-tSd|djkr^|ddtjkr^tSttj d|j dS(NitversionsLStored simulator state incompatible with simulator, please move or delete %s( tsim_sysstlenR:R9RPtVERSION_SIGNATUREtTrueR R RqRc(RrRw((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_check_version-s c Cs*|j|jr$|jdS|jditjd6tjd6tjd6dd6tj d6tj d 6t d }t d }g}xt d d D]n}|jdidd6|d6t jd6t jd6td6dd6t jd6d|d6|j|jqWg}xt d dD]}|jdidd6|d6t jd6t jd6td6dd6t jd6d|d6t|d kr#|j|jq#q#Wg}xt d dD]}|jdidd6|d6t jd6t jd6td6t jd6t jd6d|d6t|d kr|j|jqqWxrt d d D]a}|jdid!d6|d6t jd6t jd6td6t jd6t jd6d"|d6qZW|jdd#d$tjd%|d&tjtjBtjBtjBtj Bd'tj!tj"B}|j#dd(d)|d&tjtjBtjBd*||jdd+d$tjd%|d&tjtjBtjB|jdd,d&tjtjBtjBd$tj$d%||jd-it%j&d.6d/d06d/d16d/d26d3d46|jd-it%j'd.6d5d06d5d16d5d26d6d46|jd-it%j(d.6d7d06d8d16d9d26d:d46|jd-it%j(d.6d7d06d;d16d<d26d=d46|jd-it%j(d.6d7d06d>d16d<d26d=d46|jd?id@d6t)j*dA6t)jd6|jd?idBd6t)j+dA6t)jd6|jdSdS(Cs^ Raise error if version not match. If empty database found, initiate. NtsystemstidtnametstatusR#t status_infoRvtread_cache_pctt2TiBt512GiBiitdiskss2TiB SATA Diskt disk_prefixt total_spacet disk_typetvpd83i trpmt link_typesPort: %d Box: 1 Bay: 1tlocationis 2TiB SAS Diski:sPort: %d Box: 1 Bay: 2is512GiB SSD DisksPort: %d Box: 1 Bay: 3is 2TiB SSD DisksPort: %d Box: 1 Bay: 4sPool 1R<t sim_disk_idst element_typetunsupported_actionssPool 2(sub pool of Pool 1)tparent_pool_idtsizesPool 3t lsm_test_aggrttgtst port_types50:0a:09:86:99:4b:8d:c5tservice_addresstnetwork_addresstphysical_addresstFC_a_0bt physical_names50:0a:09:86:99:4b:8d:c6t FCoE_b_0cs"iqn.1986-05.com.example:sim-tgt-03s sim-iscsi-tgt-3.example.com:3260sa4:4e:31:47:f4:e0t iSCSI_c_0ds 10.0.0.1:3260sa4:4e:31:47:f4:e1t iSCSI_c_0es%[2001:470:1f09:efe:a64e:31ff::1]:3260t batteriess'Battery SIMB01, 8000 mAh, 05 March 2016Rs&Capacitor SIMC01, 500 J, 05 March 2016(,t trans_beginR{t trans_committ _data_addRPtSYS_IDtSYS_NAMERt STATUS_OKRyt_DEFAULT_READ_CACHE_PCTRR$Rt TYPE_SATAR+t LINK_TYPE_ATAR%RetTYPE_SASt LINK_TYPE_SASRxtTYPE_SSDtRPM_NON_ROTATING_MEDIUMtsim_pool_create_from_diskRRCRtELEMENT_TYPE_POOLtELEMENT_TYPE_FStELEMENT_TYPE_VOLUMEtELEMENT_TYPE_DELTAtELEMENT_TYPE_SYS_RESERVEDtUNSUPPORTED_VOLUME_GROWtUNSUPPORTED_VOLUME_SHRINKtsim_pool_create_sub_poolRBR tTYPE_FCt TYPE_FCOEt TYPE_ISCSIRt TYPE_CHEMICALtTYPE_CAPACITOR(Rrt size_bytes_2ttsize_bytes_512gt pool_1_diskstittest_pool_diskstssd_pool_diskst pool_1_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytcheck_version_and_init;s.                                                       cCs2|jj}|j||j|_|jS(s9 Execute sql command and get all output. (RhR.texecuteRetfetchall(RrRsRt((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _sql_execs  cCsd|}|j|S(NsSELECT * FROM %s(R(Rrt table_nameRs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _get_tables cCs|jjddS(NsBEGIN IMMEDIATE TRANSACTION;(RhR(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR scCs|jjdS(N(Rhtcommit(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRscCs|jjdS(N(Rhtrollback(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRscCst|j}gt|jD]$}|dkr=dn t|^q%}d|ddj|ddj|f}|j|dS(NR#s INSERT INTO %s (%s) VALUES (%s);s'%s's', '(R7R9tvaluesRdRR(R(RrRt data_dictR9tvRRs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs=cCsyd||f}|j|}|rqt|dkr;dSt|dkrU|dSttjdtn|SdS(NsSELECT * FROM %s WHERE %siis%_data_find(): Got non-unique data: %s(RRxRdR R Rtlocals(Rrttablet conditiont flag_uniqueRst sim_datas((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _data_findscCsI|dkr"d|||f}nd||||f}|j|dS(Ns#UPDATE %s SET %s=NULL WHERE id='%s's#UPDATE %s SET %s='%s' WHERE id='%s'(RdR(RrRtdata_idt column_nametvalueRs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _data_update-s  cCs!d||f}|j|dS(NsDELETE FROM %s WHERE %s;(R(RrRRRs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _data_delete7scCsH|jditjdtjd6tjd6|d6|d6|jS(s* Return a job id(Integer) tjobst LSM_SIM_TIMEtdurationt timestampt data_typeR(RR[tgetenvRPtJOB_DEFAULT_DURATIONttimeRe(Rrt job_data_typeR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_job_create;s  cCs|jdd|dS(NRsid="%s"(R(Rrt sim_job_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_job_deleteJscCsE|jdd|dt}|d kr=ttjdnttjt|d|dd}d }d }|dkrd}n|dkr8d}|d t j kr|j |d }|d }q8|d t j kr|j |d }|d }q8|d t jkr8|j|d }|d }q8n|||fS( sg Return (progress, data_type, data) tuple. progress is the integer of percent. Rsid=%sRs Job not foundRRidiRRN(RRzRdR R t NOT_FOUND_JOBRgRtfloatRPtJOB_DATA_TYPE_VOLt sim_vol_of_idtJOB_DATA_TYPE_FSt sim_fs_of_idtJOB_DATA_TYPE_FS_SNAPtsim_fs_snap_of_id(RrRtsim_jobtprogresstdataR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_job_statusMs.  )     cCs |jdS(s0 Return a list of sim_sys dict. R|(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRwpscCs$td|jdd|DS(Ncss|]}|dVqdS(t lsm_disk_idN((t.0R0((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys xst disks_viewsowner_pool_id="%s"(R7R(Rrt sim_pool_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytlsm_disk_ids_of_poolvscCs |jdS(s1 Return a list of sim_disk dict. R(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_disks|scCs |jdS(s1 Return a list of sim_pool dict. t pools_view(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_poolsscCs|jd|tjdS(NRR(t_sim_data_of_idR tNOT_FOUND_POOL(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_pool_of_idsic Cs7|dkrtj}n|tjks6|tjkrBtj}n|jdi|d6tjd6dd6|d6|d6|d 6tj d 6|d 6t j |t |}|j }x>|| D]2} |jd | d ||jd | ddqWx>||D]2} |jd | d ||jd | ddqW|S(NitpoolsR~RR#RRRR<t member_typet strip_sizeRt owner_pool_idtroletDATAtPARITY(RPtDEFAULT_STRIP_SIZERRCRAtBLK_SIZERRRtMEMBER_TYPE_DISKR4R>RxReR( RrR~RR<RRRR>Rt sim_disk_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs<       cCs_|jdi |d6tjd6dd6|d6|d6tjd6tjd 6|d 6|d 6|jS( NRR~RR#RRRR<RRR(RRRRtRAID_TYPE_OTHERtMEMBER_TYPE_POOLRe(RrR~RRRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs    cCs|jd|ddS(Ns3SELECT COUNT(id) FROM disks WHERE owner_pool_id=%s;i(R(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_pool_disks_countscCs|jd|ddS(NsCSELECT COUNT(id) FROM disks WHERE owner_pool_id=%s and role='DATA';i(R(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_pool_data_disks_countscCs+|r|jdd|S|jdSdS(s0 Return a list of sim_vol dict. tvolumes_by_ag_viewsag_id=%st volumes_viewN(RR(Rrt sim_ag_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_volsscCsO|j|d|dt}|dkrK|rDt|d|qKdSn|S(Nsid=%sRs %s not found(RRzRdR (RrRRt lsm_error_not data_nametsim_data((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs cCs|jd|tjdS(sD Return sim_vol if found. Raise error if not found. RR(RR tNOT_FOUND_VOLUME(Rrt sim_vol_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs cCs8|j|}|d|kr4ttjdndS(Nt free_spacesInsufficient space in pool(RR R tNOT_ENOUGH_SPACE(RrRt size_bytestsim_pool((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_check_pool_free_spaces cCs|tjdtjtjS(Ni(RPR(R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_block_roundingscCstj|}|j||t}t|d<||d<||d<||d<||dQsR.s ag_id="%s"(R7R(RrR ((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_vol_ids_of_masked_agOs cCs$td|jdd|DS(Ncss|]}|dVqdS(R/N((RR6((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys VsR.s vol_id="%s"(R7R(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR'Ts cCstj|}|j|}|d|krCttjdn|j|d}||d}|dkr|dtj@rttj dn|d|krttj dqn&|dtj @rttj dn|j d |d||j d |d |dS( NRs%Volume size is identical to requestedRiRs.Requested pool does not allow volume size growRsInsufficient space in poolRR( RPRRR R R2RRRt NO_SUPPORTRRR(RrRtnew_size_bytesR%Rt increment((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_resizeYs0    cCs1|j|td|jdd|DS(sL Return a list of dst_vol_id for provided source volume ID. css|]}|dVqdS(t dst_vol_idN((RR0((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys stvol_repsssrc_vol_id="%s"(RR7R(Rrtsrc_sim_vol_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR)|s  cCs|j||j|||kr*dS|tjkr=dStd|jdd|D}t|dkrydS|jdi|d6|d6|d6dS(Ncss|]}|dVqdS(t src_vol_idN((Rtr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys sR=sdst_vol_id="%s"iR?R<trep_type(RRtREPLICATE_COPYR7RRxR(RrR>R,RAt blk_rangestcur_src_sim_vol_ids((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_replicas"    cCs<|j|s$ttjdn|jdd|dS(Ns+Provided volume is not a replication sourceR=ssrc_vol_id="%s"(R)R R R2R(RrR>((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_src_replica_breaks  cCsN|j|}|d|kr4ttjdn|jd|d|dS(NRs,Volume admin state is identical to requestedR(RR R R2R(RrRtnew_admin_stateR%((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_state_changes cCs%|djtj|d<|d=|S(s= Update 'init_type' and 'init_ids' of sim_ag t init_ids_strtinit_ids(tsplitRPRn(tsim_ag((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_ag_formats cCsN|r|jdd|}n|jd}g|D]}tj|^q5S(Ntags_by_vol_views vol_id=%stags_view(RRRPRM(RrRtsim_agsta((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRPs cCs\y)|jdi|d6|d6|d6Wn,tjk rW}ttjd|nXdS(NtinitsR}t init_typet owner_ag_ids6Initiator '%s' is already in use by other access group(RRR#R R tEXISTS_INITIATOR(RrRStinit_idR R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_init_createscCsdS(N(Rd(RrRVtin_usertin_passtout_usertout_pass((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytiscsi_chap_auth_setscCsjy$|jdi|d6|j}Wn,tjk rR}ttjd|nX|j||||S(NtagsR~s1Name '%s' is already in use by other access group(RReRR#R R R$RW(RrR~RSRVR R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_ag_creates cCsI|j||j|r1ttjdn|jdd|dS(Ns!Access group has volume masked toR]sid="%s"(R1R7R R R(R(RrR ((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_ag_deletes   cCs~|j|}||dkr4ttjdn|tjkrg|tjkrgttjdn|j|||dS(NRJs!Initiator already in access groups.Only support iSCSI IQN and WWPN initiator type( R1R R R2RtINIT_TYPE_ISCSI_IQNtINIT_TYPE_WWPNR8RWRd(RrR RVRSRL((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_ag_init_adds  cCsw|j|}||dkr4ttjdnt|ddkr_ttjdn|jdd|dS(NRJs(Initiator is not in defined access groupis6Refused to remove the last initiator from access groupRRsid="%s"(R1R R R2RxtLAST_INIT_IN_ACCESS_GROUPR(RrR RVRL((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_ag_init_deletes  cCs,|jd|tjd}tj||S(NROs Access Group(RR tNOT_FOUND_ACCESS_GROUPRPRM(RrR RL((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR1s    cCs |jdS(s/ Return a list of sim_fs dict. tfss_view(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fssscCs.tj}|sd}n|jd||dS(NRfs File System(R t NOT_FOUND_FSRdR(Rrt sim_fs_idt raise_errorR ((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR"s   cCstj|}|j||y7|jdi|d6|d6|d6|d6|d6Wn,tjk r}ttjd|nX|j S(NtfssR~RRRRs'Name '%s' is already in use by other fs( RPRRRRR#R R R$Re(RrR~RRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_fs_create*s cCsI|j||j|r1ttjdn|jdd|dS(Ns*Requested file system has child dependencyRksid="%s"(Rtclone_dst_sim_fs_ids_of_srcR R R*R(RrRi((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_fs_delete=s   cCstj|}|j|}|d|krCttjdn|j|d}||dkr|d||dkrttjdn|jd|d||jd|d||jd|d|dS(NRs*File System size is identical to requestedRRsInsufficient space in poolRkR( RPRRR R R2RRR(RrRiR9tsim_fsR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_fs_resizeFs" cCs!|j||jdd|S(Nt fs_snaps_views fs_id="%s"(RR(RrRi((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_fs_snaps`s cCsJ|jd|tjd}|rF|d|krFttjdn|S(NRqsFile system snapshottfs_idsFDefined file system snapshot ID is not belong to requested file system(RR tNOT_FOUND_FS_SSR (Rrtsim_fs_snap_idRit sim_fs_snap((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRds   cCst|j|y5|jdi|d6|d6ttjd6Wn(tjk rl}ttjdnX|j S(Ntfs_snapsR~RsRs6The name is already used by other file system snapshot( RRRgRRR#R R R$Re(RrRiR~R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_snap_createos  cCs*|j||r&|j||ndS(N(RR(RrRiRutfilest restore_filestflag_all_files((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_snap_restores cCs5|j||j|||jdd|dS(NRwsid="%s"(RRR(RrRuRi((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_snap_deletes cCsd|}|j|dS(Ns&DELETE FROM fs_snaps WHERE fs_id='%s';(R(RrRiRs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_snap_del_by_fss cCsU|j||j||r3|j||n|jdi|d6|d6dS(Nt fs_clonest src_fs_idt dst_fs_id(RRR(Rrt src_sim_fs_idt dst_sim_fs_idRu((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_fs_clones  cCs*|j||r&|j||ndS(N(RR(RrRit src_fs_namet dst_fs_nameRu((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_file_clones cCs1|j|td|jdd|DS(sM Return a list of dst_fs_id for provided clone source fs ID. css|]}|dVqdS(RN((RR0((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys sRssrc_fs_id="%s"(RR7R(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRms  cCs|jdd|dS(NRssrc_fs_id="%s"(R(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_fs_src_clone_breakscCs`xYdddgD]H}d|}||rG||jtj||st exps_view(R7R(Rr((Rrs;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_expsscCs"|j|jd|tjdS(NRs NFS Export(RRR tNOT_FOUND_NFS_EXPORT(Rrt sim_exp_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt sim_exp_of_ids c Cs0|dkr dtd }n|j|y>|jdi|d6|d6|d6|d6|d6| d 6Wn(tjk r} ttjd nX|j } x,|D]$} |jd i| d 6| d 6qWx,|D]$} |jdi| d 6| d 6qWx,|D]$}|jdi|d 6| d 6qW| S(Ns /nfs_exp_%sitexpsRstexp_pathtanon_uidtanon_gidt auth_typetoptionss/Export path is already used by other NFS exporttexp_root_hoststhosttexp_idt exp_rw_hostst exp_ro_hosts( RdR+RRRR#R R R$Re(RrRiRRRRRRRRRRt root_hosttrw_hosttro_host((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_exp_createsJ       cCs%|j||jdd|dS(NRsid="%s"(RR(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_exp_deletes cCs |jdS(s0 Return a list of sim_tgt dict. t tgts_view(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_tgtsscCs |jdS(s0 Return a list of sim_bat dict. t bats_view(R(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_batsscCs'|j||jd|d|dS(NRR(RR(RrRtpdc((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_pdc_sets cCs'|j||jd|d|dS(NRR(RR(RrRtrcp((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_rcp_sets cCs'|j||jd|d|dS(NRR(RR(RrRtwcp((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsim_vol_wcp_sets (qR?R@tVERSIONR RyRRRRRRRRRtMODE_HARDWARE_RAIDtSYS_MODERtWRITE_CACHE_POLICY_AUTOR tREAD_CACHE_POLICY_ENABLEDR!tPHYSICAL_DISK_CACHE_DISABLEDR"RRnRkRBRCRFRGRHRKRLtSUPPORTED_VCR_RAID_TYPEStSUPPORTED_VCR_STRIP_SIZESRuR{RRRRRRRR:RRRRdRRRRwRRRRRRRRR RRRRORR&R-R4R5R7R'R;R)RERFRHRMRPRWR\R^R_RbRdR1RgRzRRlRnRpRrRRxR|R}R~RRRmRRRRRRRRRRR(((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRPs         *         #      )           #                   2     RcBs%eZejdejdZedZedZ edZ edZ edZ edZ edZed Zed ZdOdOd Zed d Zed dZed dZed dZedZedZed dZedZedZedZed dZedZedZ ed e!d dZ"ed dZ#ed dZ$ed dZ%ed dZ&ed dZ'ed d Z(ed d!Z)ed d"Z*ed d#Z+ed$Z,ed%Z-ed e!d&Z.ed d'Z/ed d(Z0ed d)Z1ed d*Z2ed+Z3ed d,Z4ed d-Z5ed d.Z6ed/Z7ed e!d0Z8ed d1Z9ed2Z:ed d3Z;ed d4Z<ed d5Z=ed6Z>ed7Z?ed d8Z@ed d9ZAed d:ZBed d;ZCed d<ZDed d=ZEed d>ZFed d?ZGed d@ZHedAZIedBZJedCZKedDZLedEZMedFZNed dGZOed dHZPedIZQedJZRedKZSed dLZTed dMZUed dNZVRS(Pt LSM_SIM_DATAs /lsm_sim_datacCs4yt|tj SWntk r/|nXdS(N(RgRPRkt ValueError(tlsm_idt lsm_error((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_lsm_id_to_sim_ids cCstj|ttjdS(Ns Job not found(RRR R R(tjob_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_job_id_of&scCstj|ttjdS(NsPool not found(RRR R R(R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_pool_id_of+scCstj|ttjdS(NsVolume not found(RRR R R(R0((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_vol_id_of0scCstj|ttjdS(NsFile system not found(RRR R Rh(Rs((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _sim_fs_id_of6scCstj|ttjdS(NsFile system snapshot not found(RRR R Rt(tsnap_id((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_fs_snap_id_of<scCstj|ttjdS(NsFile system export not found(RRR R R(R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_exp_id_ofCscCstj|ttjdS(NsFile system export not found(RRR R R(R/((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _sim_ag_id_ofJscCsM|dkrtj}nt|||_|jj||_||_dS(N(RdRt SIM_DATA_FILERPRRRcRR(RrRcRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRuQs     cCs&|jj||}dtj|fS(Ns JOB_ID_%0*d(RRRPRk(RrRt sim_data_idR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _job_create[s  ic Cstj|}|jj|\}}}tj}|dkrKtj}nd}|tj krrtj |}nB|tj krtj |}n!|tj krtj|}n|||fS(Nid(RRRRR t INPROGRESStCOMPLETERdRPRt_sim_vol_2_lsmRt _sim_fs_2_lsmRt_sim_fs_snap_2_lsm( RrRtflagsRRRR RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt job_status`s    cCs7|jj|jjtj||jjdS(N(RRRRRRRd(RrRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytjob_freets  cCs1t|jtt|d|_||_dS(Ni(RPRcRgRRRRRd(RrtmsR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt time_out_set{s$ cCs|jS(N(RR(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt time_out_getsc Cs@t|d|d|d|dd|ddtjd|d S( NR}R~RRt _fw_versionRvt_modet_read_cache_pctR(RRPR(tsim_sys((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_sys_2_lsms  cCstd|jjDS(Ncss|]}tj|VqdS(N(RR(RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(R7RRw(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR|scCsa|jtjkr'ttjdn|jj|jjdtjd||jj dS(NsSystem not foundR|R( R}RPRR R tNOT_FOUND_SYSTEMRRRRRd(Rrtsystemtread_pctR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytsystem_read_cache_pct_updates    c CsOt|d|d|dtjtt|dtj|dtj|dS(Nt lsm_vol_idR~RRRt lsm_pool_id(RRPRRgRR(R%((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs  cCstd|jjDS(Ncss|]}tj|VqdS(N(RR(RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(R7RR (Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRsc Cs{|d}|d}|d}|d}|d}|d}tj}|d}|d} t|||| ||||| S( NRR~RRRRRR(RPRR( RRR~RRRRtsys_idRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_pool_2_lsms         cCs=|jj|jj}|jjtd|DS(Ncss|]}tj|VqdS(N(RR(RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(RRRRR7(RrRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs   cCstj}|ddkr)|tjO}nt|d|d|dtjtt|dtj|tjd|dd|d d |d d |d S(NRRR~RRt_vpd83Rt _locationRt_rpmRt _link_typeR( RRRdt STATUS_FREERPRRgRR(tsim_diskt disk_status((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_disk_2_lsms   cCstd|jjDS(Ncss|]}tj|VqdS(N(RR(RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(R7RR(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRsc Csy|tkr|jjn|jj||tj|d|}|rM|S|jtj|} |jj | dfS(s The '_internal_use' parameter is only for SimArray internal use. This method will return the new sim_vol id instead of job_id when '_internal_use' marked as True. RN( R:RRR&RRRRPRRRd( RrRtvol_nameRtthinpRt _internal_uset_is_hw_raid_voltnew_sim_vol_idR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_creates    cCsC|jj|jjtj||j}|jj|S(N(RRR-RRRR(RrR0RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_deletes    cCs[|jjtj|}|jj|||jtj|}|jj|dfS(N( RRRRR;RRPRRRd(RrR0R9RRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_resizes  c Cs|jjtj|}|jj|}|j|||dtjdt}|jj ||||j t j |} |jj | dfS(NRR(RRRRRRRtPROVISION_FULLRzRERRPRRRd( Rrt dst_pool_idRAR?t new_vol_nameRR>t src_sim_volR,R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_replicates   cCs+|tjkr$ttjdntjS(NsSystem not found(RPRR R RR(RrRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt!volume_replicate_range_block_sizes  cCsU|jj|jjtj|tj||||j}|jj|S(N(RRRERRRR(RrRAR?R<trangesRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_replicate_range#s     cCs=|jj|jjtj|tj|jjdS(N( RRRHRRRRRRd(RrR0R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_enable5s    cCs=|jj|jjtj|tj|jjdS(N( RRRHRRRtADMIN_STATE_DISABLEDRRd(RrR0R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_disable=s    cCsFtj|}|jj|}x|D]}||kr(tSq(WtS(N(RRRR)RzR:(RrR0RR>R+R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_child_dependencyEs   cCsC|jj|jjtj||j}|jj|S(N(RRRFRRRR(RrR0RR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_child_dependency_rm`s     cCs0t|d|d|d|d|dtjS(Nt lsm_fs_idR~RRR(RRPR(Ro((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRkscCstd|jjDS(Ncss|]}tj|VqdS(N(RR(Rtf((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys ss(R7RRg(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfsqscCsm|s|jjn|jj||tj|}|rA|S|jtj|}|jj|dfS(N( RRRlRRRRPRRRd(RrRtfs_nameRRRt new_sim_fs_idR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_createus  cCsC|jj|jjtj||j}|jj|S(N(RRRnRRRR(RrRsRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_deletes    cCs[tj|}|jj|jj|||jtj|}|jj|dfS(N( RRRRRpRRPRRRd(RrRsR9RRiR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_resizes   c Cs|jjd}|r+tj|}ntj|}|jj|}|d}|j|||ddt} |jj || ||j t j | } |jj | dfS(NRRR(RRRdRRRRRRzRRRPRR( RrRRRRRuRt src_sim_fsRRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_clones    cCsj|jjd}|r+tj|}n|jjtj|||||j}|jj|S(N( RRRdRRRRRR(RrRsRRRRRuR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_file_clones    cCst|d|d|dS(Ntlsm_fs_snap_idR~R(R(Rv((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs cCs)td|jjtj|DS(Ncss|]}tj|VqdS(N(RR(Rts((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(R7RRrRR(RrRsR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_snapshotss cCsW|jj|jjtj||}|jtj|}|jj|dfS(N( RRRxRRRRPRRRd(RrRst snap_nameRRuR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_snapshot_creates   cCsO|jj|jjtj|tj||j}|jj|S(N(RRR}RRRRR(RrRsRRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_snapshot_deletes     c Csm|jjd}|r+tj|}n|jjtj||||||j}|jj|S(N( RRRdRRR|RRR( RrRsRRyRzR{RRuR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_snapshot_restores     cCstj|}|tkr+|jjn|jj|gkr{|jj|gkr{|tkrw|jjntS|tkr|jjntS(N( RRR:RRRmRrRRz(RrRsRyRRRi((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_child_dependencys   cCs|jj|j||dttkr@ttjdntj |}|jj ||jj ||j }|jj |S(s Assuming API defination is break all clone relationship and remove all snapshot of this source file system. Rs9No snapshot or fs clone target found for this file system(RRRRzR:R R R2RRRR~RR(RrRsRyRRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytfs_child_dependency_rms    c CsMt|d|d|d|d|d|d|d|d|d |d  S( Nt lsm_exp_idRRRRRRRRR(R(R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_exp_2_lsm s cCs)g|jjD]}tj|^qS(N(RRRR(RrRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytexports sc Csl|jj|jjtj||||||||| } |jj| } |jjtj| S(N(RRRRRRRR( RrRsRRRRRRRRRRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_export s   cCs7|jj|jjtj||jjdS(N(RRRRRRRd(RrRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt fs_unexport( s  cCs)t|d|d|d|dtjS(Nt lsm_ag_idR~RJRS(RRPR(RL((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt _sim_ag_2_lsm/ scCstd|jjDS(Ncss|]}tj|VqdS(N(RR(RRQ((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys 7 s(R7RRP(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR]5 scCsu|tjkr$ttjdn|jj|jj|||}|jj|}|jj t j |S(NsSystem not found( RPRR R RRRR^R1RRR(RrR~RVRSRRt new_sim_ag_idt new_sim_ag((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytaccess_group_create9 s   cCs7|jj|jjtj||jjdS(N(RRR_RRRRd(RrR/R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytaccess_group_deleteE s  cCs^tj|}|jj|jj||||jj|}|jjtj|S(N(RRRRRbR1RR(RrR/RVRSRR R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytaccess_group_initiator_addL s   cCs[tj|}|jj|jj|||jj|}|jjtj|S(N(RRRRRdR1RR(RrR/RVRSRR RL((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytaccess_group_initiator_deleteU s   cCsC|jj|jjtj|tj||jjdS(N(RRR4RRRRRd(RrR/R0R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_mask_ s     cCsC|jj|jjtj|tj||jjdS(N(RRR5RRRRRd(RrR/R0R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_unmaskh s     cCsX|jj|jjdtj|}|jjg|D]}tj|^q?S(NR (RRR RRRR(RrR/RR R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt"volumes_accessible_by_access_groupq s    cCsX|jj|jjdtj|}|jjg|D]}tj|^q?S(NR(RRRPRRRR(RrR0RRPRQ((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytaccess_groups_granted_to_volume{ s    cCs:|jj|jj||||||jjdS(N(RRR\RRd(RrRVRXRYRZR[R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytiscsi_chap_auth s    cCs7t|d|d|d|d|d|dtjS(Nt lsm_tgt_idRRRRR(R RPR(tsim_tgt((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_tgt_2_lsm s cCstd|jjDS(Ncss|]}tj|VqdS(N(RR%(Rtt((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys s(R7RR(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt target_ports scCs=|jjtj|jttjd}tj }t j }|dt j krk|jj|d}n|d}|d}|d}|}|t jks|t jkr|||||gS|t jkrttjd|dn|t jks |t jkrtj }nt|d |}|||||gS( NsPool not foundRRR<R=Rs;volume_raid_info(): Got unsupported RAID_TYPE_MIXED pool %sRR>(RRRRRR R RRPRRtOPT_IO_SIZE_UNKNOWNRRtRAID_TYPE_UNKNOWNRtRAID_TYPE_MIXEDRRCRARg(Rrtlsm_volRt min_io_sizet opt_io_sizeR<R=R((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_raid_info s4        cCs|jjtj|jttjd}|d}g}|tj kr\|dg}n1|tj kr|jj |d}n tj }|d||fS(NsPool not foundRtparent_lsm_pool_idR}R<( RRRRR}R R RRRRRtMEMBER_TYPE_UNKNOWN(Rrtlsm_poolRRt member_ids((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytpool_member_info s   cCs7|jtjkr'ttjdntjtjfS(NsSystem not found(R}RPRR R RRR(RrR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_raid_create_cap_get s  c Cs|tjkr$ttjdn|tjkr?tj}n$|tjkrcttjdn|j j d|}g|D]'}t j |j ttjd^q}x:|D]2}|jtj@sttjd|j qqWyD|j jd|d|d|d tjd tjtjBd |} Wn,tjk r]} ttjd |nX|j j| } |j| d || ddtjdtdd} |j j| } |j j t j!| S(Ns%Provided 'raid_type' is not supporteds&Provided 'strip_size' is not supportedsPool for volume %ssDisk not founds'Disk %s is not in DISK.STATUS_FREE modeR~R<RRRRs+Name '%s' is already in use by other volumeRRiRRi("RPRR R R8RtVCR_STRIP_SIZE_DEFAULTRRRRRRR}tNOT_FOUND_DISKRRRt DISK_NOT_FREERRRRRRR#R$RRRRzRRR(RrR~R<RRt pool_nameR0RtdiskRRRRR%((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_raid_create sP     1       cCs7tj|jttjd}|jj|}dS(NsVolume not found( RRR}R R RRRRd(RrtvolumeRt sim_volume_idR%((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_ident_led_on s   cCs7tj|jttjd}|jj|}dS(NsVolume not found( RRR}R R RRRRd(RrR;RR<R%((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_ident_led_off s   cCs)t|d|d|d|dtjS(Nt lsm_bat_idR~RR(RRPR(tsim_bat((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt_sim_bat_2_lsm! scCstd|jjDS(Ncss|]}tj|VqdS(N(RRA(RR&((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pys ( s(R7RR(Rr((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyR& scCs>|jjtj|jttjd}tj }tj }t }x3|jj D]"}|dt jkrUt}qUqUW|dtjkr|rtj}qn>|dtjkrtj}n|dtjkrtj}n|dtjkrtj}n|dtjkrtj}n|d||d||dgS(NsVolume not foundRRRR(RRRRR}R R RRt WRITE_CACHE_STATUS_WRITE_THROUGHtREAD_CACHE_STATUS_DISABLEDR:RRRRzRtWRITE_CACHE_STATUS_WRITE_BACKtWRITE_CACHE_POLICY_WRITE_BACKtWRITE_CACHE_POLICY_UNKNOWNtWRITE_CACHE_STATUS_UNKNOWNRtREAD_CACHE_STATUS_ENABLEDtREAD_CACHE_POLICY_UNKNOWNtREAD_CACHE_STATUS_UNKNOWN(RrR+R%twrite_cache_statustread_cache_statustflag_battery_okR@((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_cache_info* s2           cCsR|jjtj|jttjd}|jj|||jj dS(NsVolume not found( RRRRR}R R RRR(RrR;RRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt!volume_physical_disk_cache_updateL s   cCsR|jjtj|jttjd}|jj|||jj dS(NsVolume not found( RRRRR}R R RRR(RrR;RRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyt volume_write_cache_policy_updateU s   cCsR|jjtj|jttjd}|jj|||jj dS(NsVolume not found( RRRRR}R R RRR(RrR;RRR((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pytvolume_read_cache_policy_update^ s   N(WR?R@R[Rttempfilet gettempdirRRORRRRRRRRR!RuRdRRRRRRR|RRRRRRRR:RRRRRRRRRRRRRRRRRRR R R RRRRRRRRR]RRRRRRR R!R"R%R'R.R3R4R:R=R>RARRNRORPRQ(((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyRs           & 4  "(R&RRR[RRtlsmRRRRRRRRRR R R R R RRR!R+R3tobjectR4RPR(((s;/usr/lib/python2.7/site-packages/lsm/plugin/sim/simarray.pyts$     d  8_transport.pyo000064400000021714147576505410007513 0ustar00 -P`c@sddlZddlZddlZddlZddlZddlZddlmZmZddlm Z ddl m Z ddl mZdefdYZdZd ejfd YZed krejndS( iN(tLsmErrort ErrorNumber(t SocketEOF(t DataDecoder(t DataEncodert TransPortcBseZdZdZdZdZdZdZedZ dZ dZ d Z d Z dd Zd d ZdZRS(s Provides wire serialization by using json. Loosely conforms to json-rpc, however a length header was added so that we would have the ability to use non sax like json parsers, which are more abundant. s    N(t__name__t __module__t__doc__RRRR R"t staticmethodR/R0R:R=RARRERGR>(((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyRs         cCst|}|j}zxk|ddkr|ddkrh|j|d|dd|ddn|j|d|j}qW|j|dWd|jXdS( s) Test echo server for test case. R1tdoneRR2R3t errorcodeterrormsgN(RR=RERGR0(R tsrvR((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyt_servers   t_TestTransportcBs5eZdZdZdZdZdZRS(cCshtjtjtj\|_|_t|j|_tj dt d|jf|_ |j j dS(NttargetR8( Rt socketpairR#R$tcR Rtclientt threadingtThreadRQtservertstart(R ((s2/usr/lib/python2.7/site-packages/lsm/_transport.pytsetUps !cCs{ddddddg}x\|D]T}|jjd||jj\}}|j|dk|j||kqWdS( Nt0t s s{}:""sSome text messagetDEADBEEFttestid(RVR:R>t assertTrue(R ttcttR?R@((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyt test_simples  cCsd}d}|jjdi|d6|d6|jt|jjy2|jjdi|d6|d6|jjWn?tk r}|j|j|k|j|j|knXdS(NsTest error messageidRRNRO(RVR:t assertRaisesRR>R`RBR(R te_msgte_codeR((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyttest_exceptionss! c CsxtdddD]}d|}idd6dd6|d 6}tj|d t}tjt|tj|}|j t|dkx|D]}|j j |qW|j j \}}|j ||kqWdS( Niii txtdripR1idR2R3R4(trangeR5R6R7tstringRRRRR`RUtsendRVR>( R RtpayloadRRtwiretiR?R@((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyt test_slows  cCsL|jjdd|jj\}}|j|dk|jjdS(NRM(RVR:RR>R`RYtjoin(R RHR@((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyttearDowns(RIRJR[RcRgRpRr(((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyRRs   t__main__(R5RRkR%tunittestRWt lsm._commonRRRR t lsm._dataRR<RR7tobjectRRQtTestCaseRRRItmain(((s2/usr/lib/python2.7/site-packages/lsm/_transport.pyts       > _clib.so000075500000067600147576505410006211 0ustar00ELF>P@h@8@MM ]] ]  ]] ] 00$$PtdHHHQtdRtd]] ] GNUz'`'wM@{6!@! U 9$ , iF"Qe= Vf 0/__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClassesPyArg_ParseTupleAndKeywordslsm_local_disk_link_speed_getPyInt_FromLongPyList_Newlsm_error_message_getPyUnicodeUCS4_FromStringlsm_error_freePyErr_NoMemory__stack_chk_faillsm_local_disk_led_status_getlsm_local_disk_fault_led_off_Py_NoneStructlsm_local_disk_fault_led_onlsm_local_disk_ident_led_offlsm_local_disk_ident_led_onlsm_local_disk_link_type_getlsm_local_disk_rpm_getlsm_local_disk_health_status_getlsm_string_list_sizelsm_string_list_elem_getlsm_local_disk_listlsm_string_list_freelsm_local_disk_vpd83_searchlsm_local_disk_vpd83_getlsm_local_disk_serial_num_getinit_clibPy_InitModule4_64libpython2.7.so.1.0libstoragemgmt.so.1libxml2.so.2libglib-2.0.so.0libudev.so.1libyajl.so.2libc.so.6_clib.soGLIBC_2.4GLIBC_2.2.55ii Hui R] ] ] ] a h/a r/ a h/0a h/@a h/Pa h/`a h/pa h/a h/a h/a h/a h/a x/a -a Da /a (a Fb /b *b @ b /(b $8b B@b /Hb !Xb >`b /hb &xb =b 0b b `;b 0b b 9b 80b  b `8b R0b @b 6c k0c `c `5 c 0(c P8c 3@c 0Hc @Xc 0_ _ _  _  _ _ `  ` (` 0` 8` @` H` P`  X`  ``  h` p` x` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `  HHeN Ht;H5N %N @%N h%zN h%rN h%jN h%bN h%ZN h%RN h%JN hp%BN h`%:N h P%2N h @%*N h 0%"N h %N h %N h% N h%N h%M h%M h%M h%M h%M h%M h%M hp%M h`%M hP%M h@%M h0H0P H="P UH)HHw]HlL Ht]@HO H=O UH)HHHH?HHu]H7L Ht]H@=O u'H=L UHt H=I Mh]O @f.H=I t&HK HtUH=rI H]WKf.AVHH dM HH AUATUS1H dH%(HD$1LD$D$HD$HD$H|$HT$Ht$>HcAHH]HH|$xHI<EH|$HH|$IMHD$tmfDHCL HCHhHCLhHL$dH3 %(HH []A\A]A^DAE1E11H|$HtcEtHt H+HtHmtcMtImtGMtI,$u ID$LP0HjH=HIAIELP0@HEHP0@HCHP0rAE1@]f.AVHH DK HHAUATUS1H dH%(HD$1LD$D$HD$HD$zH|$HT$Ht$~HcAHHMHH|$hHI<EH|$HH|$IMHD$tmfDHCL HCHhHCLhHL$dH3 %(HH []A\A]A^DAE1E11H|$HtSEtHt H+HtHmtcMtImtGMtI,$u ID$LP0HjH=HIAIELP0@HEHP0@HCHP0rAE1@Mf.AUHH $I HHATUS1H(dH%(HD$1LD$HD$HD$tH|$Ht$HcAHHLHHEH|$HH|$IMHD$ujH+Ht HmMt I,$H=F H/uHGP0gHHL$dH3 %(HH([]A\A]fHCH]F HHCHhHCL`AE11H|$Ht&EtHNSH=HIAID$LP0@HEHP0!HCHP0lff.AUHH 4G HH ATUS1H(dH%(HD$1LD$HD$HD$H|$Ht$HcAHHlHHEH|$HH|$IMHD$ujH+Ht HmMt I,$H=D H/uHGP0HHL$dH3 %(HH([]A\A]fHCH}D HHCHhHCL`AE11H|$HtFEtHNSH=HIAID$LP0@HEHP0!HCHP0ff.AUHH DE HH*ATUS1H(dH%(HD$1LD$HD$HD$H|$Ht$HcAHHHHEH|$=HH|$IMHD$ujH+Ht HmMt I,$H=B H/uHGP0HHL$dH3 %(HH([]A\A]fHCHB HHCHhHCL`AE11H|$HtfEtHNSH=HIAID$LP0@HEHP0!HCHP0ff.AUHH TC HHJATUS1H(dH%(HD$1LD$HD$HD$H|$Ht$-HcAHHHHEH|$]HH|$I8MHD$ujH+Ht HmMt I,$H=A H/uHGP0HHL$dH3 %(HH([]A\A]fHCH@ HHCHhHCL`AE11H|$HtEtHNSH=4HIAID$LP0@HEHP0!HCHP0ff.AVHH dA HHjAUATUS1H dH%(HD$1LD$D$HD$HD$H|$HT$Ht$HcAHHHHHc|$HI;EH|$XHH|$I3MHD$tlDHCL HCHhHCLhHL$dH3 %(HH []A\A]A^DAE1E11H|$HtEtHt H+HtHmtcMtImtGMtI,$u ID$LP0[HjH= 4HIAIELP0@HEHP0@HCHP0rAE1@f.AVHH D? HHZ AUATUS1H dH%(HD$1LD$D$HD$HD$H|$HT$Ht$nHcAHHHHHc|$HI;EH|$HHH|$I#MHD$tlDHCL HCHhHCLhHL$dH3 %(HH []A\A]A^DAE1E11H|$HtEtHt H+HtHmtcMtImtGMtI,$u ID$LP0KHjH= $HIAIELP0@HEHP0@HCHP0rAE1@f.AVHH $= HHJ AUATUS1H dH%(HD$1LD$D$HD$HD$H|$HT$Ht$HcAHHHHHc|$HI;EH|$8HH|$IMHD$tlDHCL HCHhHCLhHL$dH3 %(HH []A\A]A^DAE1E11H|$HtEtHt H+HtHmtcMtImtGMtI,$u ID$LP0;HjH= HIAIELP0@HEHP0@HCHP0rAE1@f.Ht fDH=P @ATUHSDHItW1&HHHt)IT$كHH9r[]LA\I,$u ID$LP0[]1A\AVAUATUSH Ht$H|$HD$dH%(HD$1HD$HcAhHHth&HHtVH|$HIEH|$H}H|$IMHD$A#fDAE1E11H|$HtkH|$HtEtgHt H+Ht HmMt ImMtI,$tlHT$dH3%(H []A\A]A^fDHCL HCHhHCLhH@H=PHIA;DID$LP0IELP0MjlHCHP0H*0HEHP0M AE1f.AVHH 48 HHzAUATUS1H dH%(HD$1LD$H$HD$HD$H|$HT$HHcAHHHHH<$HINEH|$kH#H|$IFH<$HD$MtwHCL HCHhHCLhHL$dH3 %(HH []A\A]A^DAE1E11H|$HtH<$EtHt H+~HtHmtbMtImtFMtI,$u ID$LP0ZHafH=4HIA{DIELP0@HEHP0@HCHP0sAE18f.AVHH $6 HHZAUATUS1H dH%(HD$1LD$H$HD$HD$H|$HT$HPHcAHHHHH<$zHINEH|$KHH|$I&H<$HD$4MtwHCL HCHhHCLhHL$dH3 %(HH []A\A]A^DAE1E11H|$HtH<$EtHt H+~HtHmtbMtImtFMtI,$u ID$LP0:HafH=HIA{DIELP0@HEHP0@HCHP0sAE18f.AVHH 3 HH:AUATUS1H dH%(HD$1LD$H$HD$HD$H|$HT$HHcAHHHHH<$ZHINEH|$+HH|$IH<$HD$MtwHCL HCHhHCLhHL$dH3 %(HH []A\A]A^DAE1E11H|$HtH<$EtHt H+~HtHmtbMtImtFMtI,$u ID$LP0HafH=HIA{DIELP0@HEHP0@HCHP0sAE18}f.H52 H=$A11SHHs_clibdisk_pathvpd83_local_disk_serial_num_get_local_disk_vpd83_search_local_disk_vpd83_get_local_disk_health_status_get_local_disk_rpm_get_local_disk_list_local_disk_link_type_get_local_disk_ident_led_on_local_disk_ident_led_off_local_disk_fault_led_on_local_disk_fault_led_off_local_disk_led_status_get_local_disk_link_speed_getINTERNAL USE ONLY! Usage: Get the link speed for given disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Empty string is failure Returns: [link_speeds, rc, err_msg] link_speeds (list of string) Empty list is not support. The string is like: '3.0 Gbps' or special strings(check libstoragemgmt_types.h for detail): * LSM_DISK_LINK_SPEED_UNKNOWN -- 'UNKNOWN' * LSM_DISK_LINK_SPEED_DISABLED -- 'DISABLED' * LSM_DISK_LINK_SPEED_DISCONNECTED-- 'DISCONNECTED' rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Get LED status for given disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Empty string is failure Returns: [led_status, rc, err_msg] led_status (integer) Disk LED status which is a bit map. rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Clear the fault LED for given disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Empty string is failure Returns: [None, rc, err_msg] None rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Enable the fault LED for given disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Empty string is failure Returns: [None, rc, err_msg] None rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Clear the identification LED for given disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Empty string is failure Returns: [None, rc, err_msg] None rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Enable the identification LED for given disk. Parameters: disk_path (string) The disk path, example '/dev/sdb'. Empty string is failure Returns: [None, rc, err_msg] None rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Query the link type of given disk path Parameters: disk_path (string) The disk path, example '/dev/sdb'. Empty string is failure Returns: [link_type, rc, err_msg] link_type (int) Link type. rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Query local disk paths. Currently only SCSI, ATA and NVMe disks will be included Parameters: N/A Returns: [disk_paths, rc, err_msg] disk_paths (list of string) Empty list is not found. The string format: '/dev/sd[a-z]+' or '/dev/nvme[0-9]+n[0-9]+'. rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Query the rotation speed of given disk path Parameters: disk_path (string) The disk path, example '/dev/sdb'. Empty string is failure Returns: [rpm, rc, err_msg] rpm (int) revolutions per minute (RPM). rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Query the SCSI VPD83 NAA ID of given disk path Parameters: disk_path (string) The SCSI disk path, example '/dev/sdb'. Empty string is failure Returns: [vpd83, rc, err_msg] vpd83 (string) String of VPD83 NAA ID. Empty string if not supported. The string format regex is: (?:^6[0-9a-f]{31})|(?:^[235][0-9a-f]{15})$ rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Query the health status of a given disk path Parameters: disk_path (string) The SCSI disk path, example '/dev/sdb'. Empty string is failure Returns: [health_status, rc, err_msg] health_status (int) health status. rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Query the SCSI VPD80 serial number of given disk path Parameters: disk_path (string) The SCSI disk path, example '/dev/sdb'. Empty string is failure Returns: [serial_num, rc, err_msg] serial_num (string) String of VPD80 serial number. Empty string if not supported. rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. INTERNAL USE ONLY! Usage: Find out the /dev/sdX paths for given SCSI VPD page 0x83 NAA type ID. Considering multipath, certain VPD83 might have multiple disks associated. Parameters: vpd83 (string) The VPD83 NAA type ID. Returns: [disk_paths, rc, err_msg] disk_paths (list of string) Empty list is not found. The string format: '/dev/sd[a-z]+'. rc (integer) Error code, lsm.ErrorNumber.OK if no error err_msg (string) Error message, empty if no error. ; h`@( h0@P@pX0 PhpzRx $FJ w?;*3$"DDBVB A(A0FP 0A(A BBBF DhBVB A(A0FP 0A(A BBBF <0BVA A(FP (A ABBC <BVA A(FP (A ABBC <TpBVA A(FP (A ABBC <BVA A(FP (A ABBC DBVB A(A0FP 0A(A BBBF DxBVB A(A0FP 0A(A BBBF Dd@BVB A(A0FP 0A(A BBBF 4yBAD K AEH SADDXBBB A(A0DP5 0A(A BBBG DD0BVB A(A0FP 0A(A BBBF DBVB A(A0FP 0A(A BBBF DBVB A(A0FP 0A(A BBBF ]  (5? ` P/] ] oH ^ `   oooo6] &6FVfv&6Fh/r/h/h/h/h/h/h/h/h/h/h/x/-D/(F/*@/$B/!>/&=0`;0980 `8R0@6k0``50P30@0_clib.so.debug%IͿ7zXZִF!t/]?Eh=ڊ2Na6DgoπNY{1}\28GGq?*\^zo<e>PDRƥ0݇)Mb]AyČ s Ӱc5; ; %:3́K~&מlby(dp6 /3FVժ~\նv+|`F^WIϽ.-ŵ߯~6 z:$9X5 x[=\e#m,Pw@^~it߸v8Č@qDt1W2ͤofZ_,li".t=r x>BG@eTdmDq()ԂDCXeu@PhMϒMhYZy=_{`oL5G+:x:k6d2Z3a7)WW4核j7s Yo3x*x3gt]Xjj CsٓxI;NB:-@c,Sm?"!ѓҙDO/2gl4Hkg\x !cJh|zjwIWVQt72ltYvÒI_Ӭ#9  j0yb4PYPúн+)07*P (3^aM=a>R0M<>,˘ދdL*3uy2/$hrjk_mu,o##4f6j5}h Ti;E#OWԚv8-4*m: k<@+Wh56OwiE-P~j|F;Wnu8 5~gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.gnu_debuglink.gnu_debugdata $o$( 00HH^8oDEo0T ^Bh``cnPPtP/P/ z`/`/^ HHXIXI4] ]] ]] ]] ]] ]0_ _0` `a a c ccc|g