/usr/lib/python2.7/dist-packages/txwinrm/SessionManager.py is in python-txwinrm 1.1.28-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | ##############################################################################
#
# Copyright (C) Zenoss, Inc. 2016, all rights reserved.
#
# This content is made available according to terms specified in
# License.zenoss under the directory where your Zenoss product is installed.
#
##############################################################################
"""txsessionmgr - Python module for a single persistent connection to a device
for multiple clients.
Useful for situations when multiple connections to a device can be handled
with one connection through a single login, e.g. txciscoapic, txwinrm
The global SESSION_MANAGER is instantiated one time and is used to manage
all sessions
Session should be subclassed and implemented to login/logout, send requests,
and handle responses
A Client should always have a key property. This will be unique to the types
of transactions/requests being made through a single Session
"""
from twisted.internet.defer import inlineCallbacks, returnValue, succeed
class Session(object):
"""
Session handler for connection to a device.
deferred_init will kick off a deferred login to a device from the first
client that needs the connection. Subsequent clients will use the data
returned from the first login.
The Session class is responsible for implementing the login/logout methods
"""
def __init__(self):
# Used to keep track of clients using session
self._clients = set()
# The currently valid token. This can be anything that the client
# needs to know the connection is alive
self._token = None
# Deferred waiting for login result.
self._login_d = None
# Error from last login if applicable.
self._login_error = None
# Deferred sending a refresh/keep-alive signal/request
self._refresh_d = None
@inlineCallbacks
def deferred_login(self, client):
"""Return Deferred token
:param client: Client initiating a connection
:client: ZenPack specific client
:rtype: Deferred
:return: Returns ZenPack unique token to be used for a session.
"""
self._clients.add(client)
if self._token:
returnValue(self._token)
# No one already waiting for a token. Login to get a new one.
if not self._login_d or self._login_d.called:
self._login_d = self._deferred_login(client)
try:
self._token = yield self._login_d
except Exception as e:
self._login_error = e
raise
# At least one other client is already waiting for a token, and
# the login to get it is already in progress. Wait for that
# login to finish, then return its token.
else:
yield self._login_d
if self._login_error:
raise self._login_error
returnValue(self._token)
@inlineCallbacks
def deferred_logout(self, client):
"""Return Deferred None.
Calls session._deferred_logout() only if all other clients using the same
session have also called deferred_logout.
"""
if len(self._clients) <= 1:
if self._token:
try:
yield self._deferred_logout()
except Exception:
pass
self._token = None
if client in self._clients:
self._clients.remove(client)
returnValue(None)
@inlineCallbacks
def _deferred_login(self, client):
'''login method
Performs the ZenPack specific login to a device. This will only be called
from the first client to fire off the deferred. All other clients will
use the _token returned from this method
:param client: Client initiating a connection
:type client: ZenPack specific client
:rtype: Deferred
:return: Returns a Deferred which is logs into the device.
'''
returnValue(None)
@inlineCallbacks
def _deferred_logout(self):
'''logout method
Performs the ZenPack specific logout from a device. This will only be called
by the last client to logout of the session.
:rtype: Deferred
:return: Returns a Deferred which logs out of the device
'''
returnValue(None)
class SessionManager(object):
'''
Class to manage open sessions to devices.
'''
def __init__(self):
# Used to keep track of sessions
self._sessions = {}
def get_connection(self, key):
'''Return the session for a given key
'''
if key is None:
raise Exception('Client key cannot be empty')
return self._sessions.get(key, None)
def remove_connection(self, key):
session = self.get_connection(key)
if session:
self._sessions.pop(session)
@inlineCallbacks
def init_connection(self, client, session_class=Session):
'''Initialize connection to device.
If a session is already started return it.
Else kick off deferred to initiate session
The client must contain a key for session storage
:param client: Client initiating connection
:client: ZenPack defined client.
'''
if not hasattr(client, 'key'):
raise Exception('Client must contain a key field')
session = self.get_connection(client.key)
if session:
if session._token:
if client not in session._clients:
session._clients.add(client)
returnValue(session._token)
if session is None:
session = session_class()
self._sessions[client.key] = session
token = yield session.deferred_login(client)
returnValue(token)
@inlineCallbacks
def close_connection(self, client):
'''Kick off a session's logout
If there are no more clients using a session, remove it
:param client: Client closing connection
:client: ZenPack defined class
'''
session = self.get_connection(client.key)
if not session:
returnValue(None)
yield session.deferred_logout(client)
if not session._clients:
# no more clients so we don't need to keep the session
self._sessions.pop(client.key)
returnValue(None)
SESSION_MANAGER = SessionManager()
|