!;Vc@sOdZddlZddlZddlZddlZddlmZddlZddl Z ddl Z ddl Z ddl m Z mZmZddljjjjjjZddlmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#ddl$Z$e$j%dde&dZ'd Z(d Z)d Z*d Z+d dgZ,d Z-d Z.dZ/dZ0e0Z1ddddgZ2de j3fdYZ4de#fdYZ5de j3fdYZ6de7fdYZ8de7fdYZ9de7fd YZ:d!e7fd"YZ;d#e7fd$YZ<d%Z=e>e?e>e>d&Z@d'ZAe>e?e>e>e>d(ZBe>e?e>e>e>e>d)ZCe'd*ZDe'e>d+ZEd,ZFe)d-ZGe)e>e>d.ZHd/ZIe>d0ZJe>d1ZKe>e>d2ZLe>e>e?e>e>e>d3ZMe>e>e?e>e>e>e>d4ZNe>d5ZOe>e>d6ZPdS(7sconnect - RAD connection oriented utilities This module facilitates communication with RAD instances via a number of alternative transports. The RadConnection class acts as the primary interface and offers a connection to a RAD instance which may be used to: - locate objects - invoke object methods - read/write object properties - subscribe/unsubscribe to object events iN(tSSL(t RADPackert RADUnpackertRecordMarkingSocket( t_Opt_Schemet _RequestErrort_ErrortADRNamet RADInterfacet _raise_errort _read_timet _ADRPatterntTypet RADStructtignoretcategorys/system/volatile/rad/radsockets%/system/volatile/rad/radsocket-unauthi0iitXDRs HTTP/JSONiitsuccesss2protocol requested (%d) is too old for this servers2protocol requested (%d) is too new for this servers7encoding requested (%s) is not supported by this servert _RadReadercBs eZdZdZdZRS(se A utility class which reads RAD protocol message and posts them on for further consumption. cCs&tjj|t|_||_dS(s Create a RadReader object. N(t threadingtThreadt__init__tTruetdaemont _connection(tselft connection((s../common/connect.pyR\s cCscy9x2tr7|jj\}}|jj||qWWn#tk r^}|jj|nXdS(s1 Called when a thread is started on this object. N(RRt _read_messaget _post_messaget Exceptiont _set_error(Rtmsgtserialtexc((s../common/connect.pytrunbs  (t__name__t __module__t__doc__RR#(((s../common/connect.pyRYs tRadUpdateParametercBseZdZdZRS(s4A generic struct to use for passing _rad_update argscCst|||dS(N(tsetattr(Rtfieldtvalue((s../common/connect.pyRns(R$R%R&R(((s../common/connect.pyR'lst_RadEventReadercBs eZdZdZdZRS(s[ A utility class which reads RAD events and posts them on for further consumption. cCs&tjj|t|_||_dS(s! Create a RadEventReader object. N(RRRRRR(RR((s../common/connect.pyRus c Cs"yxtr|jj}|jjx|jjD]}|j|djkrWq5n|dj|j}d}|j dk r|j j t |jt|j |j}n$|j j t |jt|j}|d|||dq5WWdQXqWWn#tk r}|jj|nXdS(s1 Called when a thread is started on this object. iiiN(RRt _read_eventt_slockt _subscriberstsourcet_idt_eventsteventtNonetsubtypettypet_unpackRtpayloadtFalseRR(Rtevttsubt event_typetobjR"((s../common/connect.pyR#{s&     *(R$R%R&RR#(((s../common/connect.pyR+rs t RadConnectioncBseZdZededZdZdZdZ dZ dZ dZ dZ d Zd Zd Zd Zd ZdddZddZdZddZdZddZddZdZdZRS(s! A connection to a RAD instance. c Cstj|_tj|_tj|_tj|_tj|j|_tj|j|_d|_ i|_ g|_ g|_ t||_d|_d|_d}|dkrttj}|ddgkrd}q|ddkrd|dN(RGR3(Rtstate((s../common/connect.pyt__repr__s cCst|j-|js2t||_|jjnWdQX|j-|jsjt||_|jjnWdQXdS(s Start our reader thread. N(RCRJRtstartR-RKR+(R((s../common/connect.pyR`s    cCsD|j5|jrdS||_|jj|jjWdQXdS(s Set our closed error state. N(RBRGREt notifyAllRF(Rterr((s../common/connect.pyRs     cCs/|jr!tt|jn|jdS(s@ If we are closed, raise an IOError. Wait on the supplied cond. N(RGtIOErrortstrtwait(Rtcond((s../common/connect.pyt_wait_until_closeds cCs2|jjt|jj}||jfS(s Read a RAD protocol message. (RIt skip_recordRt read_recordt unpack_hyper(Rt munpacker((s../common/connect.pyR s cCs`|jQ|dkr<|jjt||jjn||j|<|jjWdQXdS(s Post a RAD protocol message, supplied in packed. If serial is not 0, then it is a request response from the server, otherwise it is an event response from the server. iN(RBR1tappendtRadEventRERxRHRF(RtpackedR!((s../common/connect.pyRs    cCsK|j}|j}|tjkr8|j||St||dS(s7 Unpack a RAD protocol message, supplied in munpacker. N(t unpack_intt unpack_opaqueRtOKtresetR(RRterrorR7((s../common/connect.pyt_unpack_messages    cCs|jR|jsW|j\}}||krJtd||fn|j|SWdQX|jJx#||jkr|j|jqjW|jj |}|j|SWdQXdS(sv Read a RAD protocol response and return the unpacked message. Ensure the serial number matches reqserial.s%Bad response (serial %d, expected %d)N( RCRJRRRRBRHR~RFtpop(Rt reqserialRR!((s../common/connect.pyt_read_response)s    cCsy|jj|j}t}|j||j||j||jd7_|jj|jt |SWdQXdS(s Write a RAD protocol request and return the allocated serial number. The operation and buffer are packed before transmission.iN( RAR_Rt pack_hypert pack_enumt pack_opaqueRItwritet get_bufferR(RtopcodeRhR!trpacker((s../common/connect.pyt _make_request:s      cCsP|jAx)t|jdkr5|j|jq W|jjdSWdQXdS(s} Perform a blocking read for an event. Arguments: Returns: RadEvent: A RAD event. iN(RBtlenR1R~RER(R((s../common/connect.pyR,Hs cCs"t}i}|j}|dk r0|j}n|j|j|jt|jt|x2|jD]'}|j||j|j|qjWx,|D]$}|j||j||qW|st |j }d|d maximum supported by client (%d).isError listing %s: %sN(Rt_nameR3t_kvst pack_stringt_domaint pack_uintRt_kvpairsRLt_versionRStpack_intt get_schemeRtGLOBRRtLISTRRRR R{t get_messaget unpack_uinttrangeRRR6R8(RtproxytpatternRetlpackertsuffixtnametkeytsert lunpackertextnamestncountti((s../common/connect.pyt list_objectsWsF           #c Cst|tr!|j}|}n:t|trE|j}|j}ntdt||dk rt|j |j j d|}t|t r|j j |jqt|tr|j j |qtdt|nt}|j|j |jt|j x2|j D]'}|j||j|j |q!W|j|jd|j|jd|jtj|j}y|j|}Wn6tk r} t| dt|| jfnX|||j||jS(s; Return a RadInterface which is identified by this name. Arguments: tgt: ADRName or Proxy a RAD ADRName or a Proxy object (for singletons) suffix: _ADRPattern or a dict a name suffix Returns: RadInterface a RADInterface object sillegal tgt, %s.Rsillegal suffix, %s.iisError getting %s: %sN(t isinstanceRt_proxyR t __class__RRSR{R3RRtcopyR tupdateRtdictRRRRRRRRtLOOKUPRRRR RR( RttgtRRRtgpackerRRt gunpackerR((s../common/connect.pyt get_objects<         cCs1g}x$|D]}|j|j|q W|S(s Return a list of RadInterfaces based on the list of ADRNames/Proxies Arguments: names: list of ADRName/Proxies a list of ADRName/Proxies Returns: list of RADInterfaces a list of RADInterface objects (RR(RRtresR((s../common/connect.pyt get_objectss cCs|j|}|j|S(s1 Create an object, based on a prototype. Arguments: tgt: prototype object a prototype of the object args: list of constructor arguments a list of arguments Returns: object of type tgt a proxy to the new server object (Rt _rad_create(RRtargstproto((s../common/connect.pyt create_objectscCs |jS(s Delete an object. Arguments: tgt: object to be deleted object Returns: None (t _rad_delete(RR((s../common/connect.pyt delete_objects cCs5x%|D]}t|||||sN(tfiltertdirRtgetattrtextend(RRtmethod((s../common/connect.pyt__register_schemess cCsc|jdkr't|j|j}n]|jdkrNt|j|j}n6|jdkrut|j|j}nt|j}|j dk r_|dk r?|j dkrddl j }|j |}y|j|j|jWq<tk r}|jtdt|q<Xq\|jtd|jq_|jtd |jn|S( s Connect to a RAD instance at the specified URI. Arguments: cred Credentials, required for authentication Returns: RadConnection: a connection to RAD RRRRiNsAuthentication failed: %ss&Unrecognised authentication method: %ss5Authentication parameter is required for this URI: %s(Rt connect_tcpRRt connect_tlst connect_sshRt connect_unixRRR3trad.authRtRadAutht pam_logintpasswRRnRSR{R(RtcredtcontradaRte((s../common/connect.pytconnects2     (sradsradsssshR(spamN(R$R%t RAD_SCHEMESRRRR3R(((s../common/connect.pyRs  L t_ZonesBridgePseudoSocketcBsGeZdZddZdZdZdZdZdZ RS(s A class which implements a sufficient amount of the socket.socket interface to allow a zonesbridge.IO object communicate like a RecordMarkingSocket. cCs"||_|j|||_dS(N(t_ziotopenRadt_token(RtziotzoneR((s../common/connect.pyRs cCs|S(N((R((s../common/connect.pyRmscCs|jtS(N(RnR8(RRoRpRq((s../common/connect.pyRr"s cCs|jj|j|S(N(RRR!(RR((s../common/connect.pyRP&scCs|jj|j|dS(N(RRR!(RRh((s../common/connect.pyRY)scCs|jj|jdS(N(RRnR!(R((s../common/connect.pyRn,sN( R$R%R&R3RRmRrRPRYRn(((s../common/connect.pyRs     cCs(|dk r$|ddkr$||S|S(s Return a path rooted at root. iRN(R3(trootR((s../common/connect.pyt _map_path3scCst|ddt|ddt|dg}|d k rlxX|D]"}|jdt||gqCWn+|jdt|ddt|dg|r|jdgn|d k r|j|n|jd d g|S( s Get a List[string] suitable to use when spawning a RAD process via subprocess.Popen(). Arguments: modules List[string], a list of modules to load debug boolean, run the spawned RAD process in debug mode root string, root directory to use for the spawned RAD process auxargs List[string], additional argument to supply to the spawned RAD process Returns: List[string]: A list containing a command plus arguments s/usr/lib/rad/rads-Ms"/usr/lib/rad/transport/mod_pipe.sos&/usr/lib/rad/protocol/mod_proto_rad.sos-ms/usr/lib/rad/modules/usr/lib/rad/site-moduless-ds-ts stdin:exitN(R%R3R (tmodulestdebugR$tauxargstcmdtmodule((s../common/connect.pyt build_rad_cmd=s   # cGsK|dk rd||f}ndddddd|g}|j||S( s Get a command to ssh to the given host as the given user and run the given command remotely Arguments: host string, target host user string, remote user, or None to connect as the local user *remote_cmd arbitrary argument list, an optional command to run remotely Returns: List[string]: A list containing a command plus arguments s%s@%ss /usr/bin/sshs-qs-etnones-os BatchMode yesN(R3R (RRt remote_cmdR)((s../common/connect.pyt build_ssh_cmdds   cCsFt||||}tj|ddtjtjd|}t|S(st Get a transport suitable for connecting to a privately spawned RAD process. Arguments: modules List[string], a list of modules to load, or all system modules if not specified debug boolean, run the spawned RAD process in debug mode env Dictionary[string, string], environment for the spawned RAD process root string, root directory to use for the spawned RAD process auxargs List[string], additional argument to supply to the spawned RAD process Returns: ProcessPseudoSocket: a "socket" for a spawned RAD process itenvN(R+t subprocesstPopenR3tPIPER(R&R'R/R$R(R)Ra((s../common/connect.pyt_get_private_transports cCs(t|||||}t|d|S(s1 Connect to a privately spawned instance of RAD using a pipe. Arguments: modules List[string], a list of modules to load debug boolean, run the spawned RAD process in debug mode env Dictionary[string, string], environment for the spawned RAD process root string, root directory to use for the spawned RAD process auxargs List[string], additional argument to supply to the spawned RAD process locale string, locale Returns: RadConnection: a connection to RAD Rc(R3R=(R&R'R/R$R(RcRa((s../common/connect.pytconnect_privatescCs)tjtjtj}|j||S(s Get a transport suitable for connecting to a local RAD instance. Arguments: path string, path to the socket Returns: socket.socket: a Unix Domain(AF_UNIX) socket (tsockettAF_UNIXt SOCK_STREAMR(RRa((s../common/connect.pyt_get_unix_transports  cCst|}t|d|S(s Connect to a RAD instance over a Unix Domain Socket. Arguments: path string, path to the socket locale string, locale Returns: RadConnection: a connection to RAD Rc(R8R=(RRcRa((s../common/connect.pyRs cCs |dkS(so callback for certificate validation should return true if verification passes and false otherwise i((tconntx509terrnoterrdepthtretcode((s../common/connect.pyt_tls_verify_cbscCstjtj}|jtj|jtj|jtj|dk rq|jtj t |j |nt j t j t j}tj||}|j||f|j|S(s Get a TLS transport suitable for connecting to a remote host. Arguments: host string, target host port int, target port Returns: SSL.Connection: a TLS based socket N(RtContextt SSLv23_METHODt set_optionst OP_NO_SSLv2t OP_NO_SSLv3t OP_NO_TLSv1R3t set_verifyt VERIFY_PEERR>tload_verify_locationsR5tAF_INETR7t ConnectionRt do_handshake(Rtca_certsRtcontextRa((s../common/connect.pyt_get_tls_transports  cCs"t|||}t|d|S(s  Connect to a RAD instance over TLS. Arguments: host string, target host port int, target port locale string, locale ca_certs string, path to file containing CA certificates Returns: RadConnection: a connection to RAD Rc(RMR=(RRRcRKRa((s../common/connect.pyRscCs/tjtjtj}|j||f|S(s Get a TCP transport suitable for connecting to a remote host. Arguments: host string, target host port int, target port Returns: socket.socket: a socket (R5RHR7R(RRRa((s../common/connect.pyt_get_tcp_transport)s cCst||}t|d|S(s Connect to a RAD instance over TCP. Arguments: host string, target host port int, target port locale string, locale Returns: RadConnection: a connection to RAD Rc(RNR=(RRRcRa((s../common/connect.pyR>scCs=t||d}tj|ddtjtj}t|S(sA Get an SSH transport to a remote (unix domain socket) rad daemon. Arguments: host string, target host running a local (unix domain socket) rad daemon user string, remote user, or None to connect as the local user Returns: ProcessPseudoSocket: a "socket" for a spawned RAD process s/usr/lib/rad/radpipeiN(R.R0R1R3R2R(RRR)Ra((s../common/connect.pyt_get_ssh_transportPs !cCst||}t|d|S(s Connect to a remote host's (unix domain socket) rad daemon through SSH. The SSH connection must use non-interactive (i.e. agent-based) authentication and should not emit any output other than that of the remote rad daemon. Arguments: host string, target host running a local (unix domain socket) rad daemon user string, remote user, or None to connect as the local user locale string, locale Returns: RadConnection: a connection to RAD Rc(ROR=(RRRcRa((s../common/connect.pyResc CsLt||t||||}tj|ddtjtj}t|S(s Get an SSH transport to a remote private copy of rad. Arguments: host string, target host user string, remote user, or None to connect as the local user modules List[string], a list of modules to load, or all system modules if not specified debug boolean, run the spawned RAD process in debug mode env Dictionary[string, string], environment for the spawned RAD process root string, root directory to use for the spawned RAD process auxargs List[string], additional argument to supply to the spawned RAD process Returns: ProcessPseudoSocket: a "socket" for a spawned RAD process iN(R.R+R0R1R3R2R( RRR&R'R/R$R(R)Ra((s../common/connect.pyt_get_ssh_private_transportys !c Cs.t|||||||}t|d|S(s} Connect to a privately spawned copy of rad on a remote host through SSH. The SSH connection must use non-interactive (i.e. agent-based) authentication and should not emit any output other than that of the remote rad daemon. Arguments: host string, target host user string, remote user, or None to connect as the local user modules List[string], a list of modules to load, or all system modules if not specified debug boolean, run the spawned RAD process in debug mode env Dictionary[string, string], environment for the spawned RAD process root string, root directory to use for the spawned RAD process auxargs List[string], additional argument to supply to the spawned RAD process locale string, locale Returns: RadConnection: a connection to RAD Rc(RPR=( RRR&R'R/R$R(RcRa((s../common/connect.pytconnect_ssh_privates cCs%|jtj}t|||S(s Get a transport suitable for connecting to a local zone. Arguments: rcon RadConnection, Connection to a global zone zone string, Name of a local zone user string, user name Returns: _ZonesBridgePseudoSocket: a "socket" for a local zone (Rt zonesbridgetIOR(trconR#RR"((s../common/connect.pyt_get_zone_transportscCs"t|||}t|d|S(s Connect to a RAD instance in a local zone. Arguments: rcon RadConnection, Connection to a global zone zone string, Name of a local zone user string, user name locale string, locale Returns: RadConnection: a connection to RAD Rc(RUR=(RTR#RRcRa((s../common/connect.pyt connect_zones(QR&RRcRMRR5tOpenSSLRRQR0RRtrad.encodings.xdrRRRt1rad.bindings.com.oracle.solaris.rad.zonesbridge_1tbindingstcomtoracletsolarisRt zonesbridge_1RRtclientRRRRRR R R R R RtwarningstfilterwarningstDeprecationWarningRtRAD_PATH_AFUNIX_UNAUTHRRtRAD_PROTO_ENCODE_HTTP_JSONR^RZt RAD_PROTO_HANDSHAKE_ERR_OLDPROTOt RAD_PROTO_HANDSHAKE_ERR_NEWPROTOR\R[R]RRR'R+tobjectR=RRRRR%R3R8R+R.R3R4R8RR>RMRRNRRORRPRQRURV(((s../common/connect.pyt%sz        L   !+ '     #     #